Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
spider.qc
Go to the documentation of this file.
1#include "spider.qh"
2
3#ifdef SVQC
5
7string autocvar_g_monster_spider_loot = "health_medium";
19
21
23
24REGISTER_MUTATOR(spiderweb, true);
25
26MUTATOR_HOOKFUNCTION(spiderweb, PlayerPhysics_UpdateStats)
27{
28 entity player = M_ARGV(0, entity);
29
30 if (StatusEffects_active(STATUSEFFECT_Webbed, player))
31 STAT(MOVEVARS_HIGHSPEED, player) *= 0.5;
32}
33
34MUTATOR_HOOKFUNCTION(spiderweb, MonsterMove)
35{
36 entity mon = M_ARGV(0, entity);
37
38 if (StatusEffects_active(STATUSEFFECT_Webbed, mon))
39 {
40 M_ARGV(1, float) *= 0.5; // run speed
41 M_ARGV(2, float) *= 0.5; // walk speed
42 }
43}
44
45SOUND(SpiderAttack_FIRE, W_Sound("electro_fire2"));
46
47METHOD(SpiderAttack, wr_think, void(SpiderAttack thiswep, entity actor, .entity weaponentity, int fire))
48{
49 TC(SpiderAttack, thiswep);
50 bool isPlayer = IS_PLAYER(actor);
51 if (fire & 1)
52 if ((!isPlayer && time >= actor.spider_web_delay) || (isPlayer && weapon_prepareattack(thiswep, actor, weaponentity, false, autocvar_g_monster_spider_attack_web_delay)))
53 {
54 if (!isPlayer)
55 {
56 actor.spider_web_delay = time + autocvar_g_monster_spider_attack_web_delay;
57 setanim(actor, actor.anim_shoot, true, true, true);
58 if (actor.animstate_endtime > time)
59 actor.anim_finished = actor.animstate_endtime;
60 else
61 actor.anim_finished = time + 1;
62 actor.attack_finished_single[0] = actor.anim_finished + 0.2;
63 }
64 if (isPlayer)
65 actor.enemy = Monster_FindTarget(actor);
66 monster_makevectors(actor, actor.enemy);
67 W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_SpiderAttack_FIRE, CH_WEAPON_B, 0, DEATH_MONSTER_SPIDER.m_id);
68 if (!isPlayer)
69 w_shotdir = normalize((actor.enemy.origin + '0 0 10') - actor.origin);
71 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
72 return;
73 }
74 if (fire & 2)
75 if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, true, 0.5))
76 {
77 if (isPlayer)
78 {
79 actor.enemy = Monster_FindTarget(actor);
80 actor.attack_range = 60;
81 }
82 Monster_Attack_Melee(actor, actor.enemy, autocvar_g_monster_spider_attack_bite_damage, ((random() > 0.5) ? actor.anim_melee : actor.anim_shoot), actor.attack_range, autocvar_g_monster_spider_attack_bite_delay, DEATH_MONSTER_SPIDER.m_id, true);
83 weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, 0, w_ready);
84 }
85}
86
88{
89 return (e != WarpZone_SearchInRadius_otherent && e.takedamage && e.monsterdef != MON_SPIDER
90 && !IS_DEAD(e) && GetResource(e, RES_HEALTH) > 0);
91}
93{
94 if (!this)
95 return;
96
97 Send_Effect(EFFECT_ELECTRO_IMPACT, this.origin, '0 0 0', 1);
98 RadiusDamage(this, this.realowner,
99 0,
100 0,
101 25,
102 NULL,
103 NULL,
104 25,
106 DMG_NOWEP,
107 NULL
108 );
109
111 for (entity head = WarpZone_SearchInRadius(this.origin, 25, MOVE_NOTHING, M_Spider_Attack_Web_Explode_cond); head; head = head.chain)
113
114 delete(this);
115}
116
121
128
130{
131 sound(this, CH_SHOTS, SND_SpiderAttack_FIRE, VOL_BASE, ATTEN_NORM);
132
133 entity proj = new(plasma);
134 proj.owner = proj.realowner = this;
137 proj.bot_dodge = true;
138 proj.bot_dodgerating = 0;
139 proj.nextthink = time + 5;
141 proj.projectiledeathtype = DEATH_MONSTER_SPIDER.m_id;
142 setorigin(proj, CENTER_OR_VIEWOFS(this));
143
144 //proj.glow_size = 50;
145 //proj.glow_color = 45;
149 setsize(proj, '-4 -4 -4', '4 4 4');
150 proj.takedamage = DAMAGE_NO;
151 proj.damageforcescale = 0;
152 SetResourceExplicit(proj, RES_HEALTH, 500);
153 proj.event_damage = func_null;
154 proj.flags = FL_PROJECTILE;
155 IL_PUSH(g_projectiles, proj);
156 IL_PUSH(g_bot_dodge, proj);
157 proj.damagedbycontents = true;
159
160 proj.bouncefactor = 0.3;
161 proj.bouncestop = 0.05;
162 proj.missile_flags = MIF_SPLASH | MIF_ARC;
163
164 CSQCProjectile(proj, true, PROJECTILE_ELECTRO, true);
165}
166
167bool M_Spider_Attack(int attack_type, entity actor, entity targ, .entity weaponentity)
168{
169 Weapon wep = WEP_SPIDER_ATTACK;
170 switch (attack_type)
171 {
173 wep.wr_think(wep, actor, weaponentity, 2);
174 return true;
175
177 if (vdist(actor.enemy.origin - actor.origin, <=, autocvar_g_monster_spider_attack_web_range))
178 {
179 wep.wr_think(wep, actor, weaponentity, 1);
180 return true;
181 }
182 }
183
184 return false;
185}
186
187spawnfunc(monster_spider)
188{
189 Monster_Spawn(this, true, MON_SPIDER);
190}
191
192METHOD(Spider, mr_think, bool(Spider this, entity actor))
193{
194 TC(Spider, this);
195 return true;
196}
197
198METHOD(Spider, mr_pain, float(Spider this, entity actor, float damage_take, entity attacker, float deathtype))
199{
200 TC(Spider, this);
201 setanim(actor, ((random() > 0.5) ? actor.anim_pain2 : actor.anim_pain1), true, true, false);
202 actor.pain_finished = actor.animstate_endtime;
203 return damage_take;
204}
205
206METHOD(Spider, mr_death, bool(Spider this, entity actor))
207{
208 TC(Spider, this);
209 setanim(actor, ((random() > 0.5) ? actor.anim_die2 : actor.anim_die1), false, true, true);
210 return true;
211}
212#endif // SVQC
213#ifdef GAMEQC
214METHOD(Spider, mr_anim, bool(Spider this, entity actor))
215{
216 TC(Spider, this);
217 vector none = '0 0 0';
218 actor.anim_melee = animfixfps(actor, '0 1 5', none); // analyze models and set framerate
219 actor.anim_die1 = animfixfps(actor, '1 1 1', none);
220 actor.anim_die2 = animfixfps(actor, '2 1 1', none);
221 actor.anim_shoot = animfixfps(actor, '3 1 1', none);
222 //actor.anim_fire2 = animfixfps(actor, '4 1 1', none);
223 actor.anim_idle = animfixfps(actor, '5 1 1', none);
224 //actor.anim_sight = animfixfps(actor, '6 1 1', none);
225 actor.anim_pain1 = animfixfps(actor, '7 1 1', none);
226 actor.anim_pain2 = animfixfps(actor, '8 1 1', none);
227 //actor.anim_pain3 = animfixfps(actor, '9 1 1', none);
228 actor.anim_walk = animfixfps(actor, '10 1 1', none);
229 actor.anim_run = animfixfps(actor, '10 1 1', none); // temp?
230 //actor.anim_forwardright = animfixfps(actor, '11 1 1', none);
231 //actor.anim_walkright = animfixfps(actor, '12 1 1', none);
232 //actor.anim_walkbackright = animfixfps(actor, '13 1 1', none);
233 //actor.anim_walkback = animfixfps(actor, '14 1 1', none);
234 //actor.anim_walkbackleft = animfixfps(actor, '15 1 1', none);
235 //actor.anim_walkleft = animfixfps(actor, '16 1 1', none);
236 //actor.anim_forwardleft = animfixfps(actor, '17 1 1', none);
237 return true;
238}
239#endif // GAMEQC
240#ifdef SVQC
241METHOD(Spider, mr_setup, bool(Spider this, entity actor))
242{
243 TC(Spider, this);
244 if (!GetResource(this, RES_HEALTH))
246 if (!actor.speed) actor.speed = autocvar_g_monster_spider_speed_walk;
247 if (!actor.speed2) actor.speed2 = autocvar_g_monster_spider_speed_run;
248 if (!actor.stopspeed) actor.stopspeed = autocvar_g_monster_spider_speed_stop;
249 if (!actor.damageforcescale) actor.damageforcescale = autocvar_g_monster_spider_damageforcescale;
250
251 actor.monster_loot = autocvar_g_monster_spider_loot;
252 actor.monster_attackfunc = M_Spider_Attack;
253
254 return true;
255}
256#endif // SVQC
257#ifdef MENUQC
258METHOD(Spider, describe, string(Spider this))
259{
260 TC(Spider, this);
262 PAR(_("The Spider is a large mechanically-enhanced arachnoid adept at hunting speedy enemies."));
263 PAR(_("To slow down its target, the Spider launches a synthetic web-like substance from its cannons. "
264 "Approaching its enwebbed prey, the Spider will inflict a series of high damage bites."));
265 return PAGE_TEXT;
266}
267#endif // MENUQC
#define setanim(...)
Definition anim.qh:45
IntrusiveList g_bot_dodge
Definition api.qh:150
#define REGISTER_MUTATOR(...)
Definition base.qh:295
#define MUTATOR_HOOKFUNCTION(...)
Definition base.qh:335
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
Definition weapon.qh:42
virtual void wr_think()
(SERVER) logic to run every frame
Definition weapon.qh:98
#define M_ARGV(x, type)
Definition events.qh:17
#define IS_DEAD(s)
Definition player.qh:244
#define IS_PLAYER(s)
Definition player.qh:242
const int FL_PROJECTILE
Definition constants.qh:77
vector v_up
float time
vector v_forward
vector origin
void CSQCProjectile(entity e, float clientanimate, int type, float docull)
float RadiusDamage(entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype,.entity weaponentity, entity directhitentity)
Definition damage.qc:937
IntrusiveList g_damagedbycontents
Definition damage.qh:143
#define DMG_NOWEP
Definition damage.qh:104
void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt)
Definition all.qc:155
SetResourceExplicit(ent, RES_ARMOR, ReadByte() *DEC_FACTOR)) ENTCS_PROP(NAME
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define TC(T, sym)
Definition _all.inc:82
#define STAT(...)
Definition stats.qh:94
entity WarpZone_SearchInRadius(vector org, float rad, float nomonsters, WarpZone_FindRadius_cond_callback_t cb)
Modified findradius aware of warpzones, that only includes entities that meet the "cb" criteria.
Definition common.qc:680
noref entity WarpZone_SearchInRadius_otherent
Free to use in the callback.
Definition common.qh:71
#define MOVE_NOTHING
Definition common.qh:35
float random(void)
vector normalize(vector v)
vector animfixfps(entity e, vector a, vector b)
Definition util.qc:1917
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
const int MOVETYPE_BOUNCE
Definition movetypes.qh:143
var void func_null()
#define METHOD(cname, name, prototype)
Definition oo.qh:274
#define NULL
Definition post.qh:14
const int PROJECTILE_ELECTRO
Definition projectiles.qh:3
#define setthink(e, f)
vector
Definition self.qh:96
entity entity toucher
Definition self.qh:76
#define settouch(e, f)
Definition self.qh:77
void adaptor_think2use_hittype_splash(entity this)
Definition common.qc:106
const int MIF_SPLASH
Definition common.qh:58
int projectiledeathtype
Definition common.qh:33
#define PROJECTILE_TOUCH(e, t)
Definition common.qh:40
IntrusiveList g_projectiles
Definition common.qh:70
const int MIF_ARC
Definition common.qh:59
#define PROJECTILE_MAKETRIGGER(e)
Definition common.qh:46
const float VOL_BASE
Definition sound.qh:36
const int CH_SHOTS
Definition sound.qh:14
const float ATTEN_NORM
Definition sound.qh:30
#define sound(e, c, s, v, a)
Definition sound.qh:52
const int CH_WEAPON_B
Definition sound.qh:8
string W_Sound(string w_snd)
Definition all.qc:226
#define SOUND(name, path)
Definition all.qh:30
#define spawnfunc(id)
Definition spawnfunc.qh:107
float autocvar_g_monster_spider_attack_bite_delay
Definition spider.qc:10
float autocvar_g_monster_spider_damageforcescale
Definition spider.qc:8
string autocvar_g_monster_spider_loot
Definition spider.qc:7
void M_Spider_Attack_Web_Explode_use(entity this, entity actor, entity trigger)
Definition spider.qc:117
float autocvar_g_monster_spider_attack_web_delay
Definition spider.qc:14
float autocvar_g_monster_spider_attack_web_speed
Definition spider.qc:12
bool M_Spider_Attack(int attack_type, entity actor, entity targ,.entity weaponentity)
Definition spider.qc:167
float autocvar_g_monster_spider_speed_stop
Definition spider.qc:16
float autocvar_g_monster_spider_speed_run
Definition spider.qc:17
bool M_Spider_Attack_Web_Explode_cond(entity e)
Definition spider.qc:87
void M_Spider_Attack_Web(entity this)
Definition spider.qc:129
float spider_web_delay
Definition spider.qc:20
float autocvar_g_monster_spider_speed_walk
Definition spider.qc:18
float autocvar_g_monster_spider_health
Definition spider.qc:6
void M_Spider_Attack_Web_Explode(entity this)
Definition spider.qc:92
float autocvar_g_monster_spider_attack_web_range
Definition spider.qc:15
void M_Spider_Attack_Web_Touch(entity this, entity toucher)
Definition spider.qc:122
float autocvar_g_monster_spider_attack_bite_damage
Definition spider.qc:9
float autocvar_g_monster_spider_attack_web_damagetime
Definition spider.qc:11
float autocvar_g_monster_spider_attack_web_speed_up
Definition spider.qc:13
bool StatusEffects_active(StatusEffect this, entity actor)
void StatusEffects_apply(StatusEffect this, entity actor, float eff_time, int eff_flags)
#define PAGE_TEXT
Definition string.qh:651
#define PAR(...)
Adds an individually translatable paragraph to PAGE_TEXT without having to deal with strcat and sprin...
Definition string.qh:657
#define PAGE_TEXT_INIT()
Definition string.qh:650
const int DAMAGE_NO
Definition subs.qh:79
bool Monster_Spawn(entity this, bool check_appear, Monster mon)
Setup the basic required properties for a monster.
entity Monster_FindTarget(entity this)
void monster_makevectors(entity this, entity targ)
bool Monster_Attack_Melee(entity this, entity targ, float damg, vector anim, float er, float animtime, int deathtype, bool dostop)
const int MONSTER_ATTACK_MELEE
const int MONSTER_ATTACK_RANGED
entity realowner
void W_SetupProjVelocity_Explicit(entity proj, vector dir, vector upDir, float pSpeed, float pUpSpeed, float pZSpeed, float spread, float forceAbsolute)
Definition tracing.qc:188
vector w_shotdir
Definition tracing.qh:20
#define W_SetupShot_Dir(ent, wepent, s_forward, antilag, recoil, snd, chan, maxdamage, deathtype)
Definition tracing.qh:32
#define CENTER_OR_VIEWOFS(ent)
Definition utils.qh:31
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt().
Definition vector.qh:8
void weapon_thinkf(entity actor,.entity weaponentity, WFRAME fr, float t, void(Weapon thiswep, entity actor,.entity weaponentity, int fire) func)
bool weapon_prepareattack(Weapon thiswep, entity actor,.entity weaponentity, bool secondary, float attacktime)
void w_ready(Weapon thiswep, entity actor,.entity weaponentity, int fire)