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 if (!this)
90 return;
91
92 Send_Effect(EFFECT_ELECTRO_IMPACT, this.origin, '0 0 0', 1);
93 RadiusDamage(this, this.realowner,
94 0,
95 0,
96 25,
97 NULL,
98 NULL,
99 25,
101 DMG_NOWEP,
102 NULL
103 );
104
105 FOREACH_ENTITY_RADIUS(this.origin, 25, it != this && it.takedamage && !IS_DEAD(it) && GetResource(it, RES_HEALTH) > 0 && it.monsterdef != MON_SPIDER,
107
108 delete(this);
109}
110
115
122
124{
125 sound(this, CH_SHOTS, SND_SpiderAttack_FIRE, VOL_BASE, ATTEN_NORM);
126
127 entity proj = new(plasma);
128 proj.owner = proj.realowner = this;
131 proj.bot_dodge = true;
132 proj.bot_dodgerating = 0;
133 proj.nextthink = time + 5;
135 proj.projectiledeathtype = DEATH_MONSTER_SPIDER.m_id;
136 setorigin(proj, CENTER_OR_VIEWOFS(this));
137
138 //proj.glow_size = 50;
139 //proj.glow_color = 45;
143 setsize(proj, '-4 -4 -4', '4 4 4');
144 proj.takedamage = DAMAGE_NO;
145 proj.damageforcescale = 0;
146 SetResourceExplicit(proj, RES_HEALTH, 500);
147 proj.event_damage = func_null;
148 proj.flags = FL_PROJECTILE;
149 IL_PUSH(g_projectiles, proj);
150 IL_PUSH(g_bot_dodge, proj);
151 proj.damagedbycontents = true;
153
154 proj.bouncefactor = 0.3;
155 proj.bouncestop = 0.05;
156 proj.missile_flags = MIF_SPLASH | MIF_ARC;
157
158 CSQCProjectile(proj, true, PROJECTILE_ELECTRO, true);
159}
160
161bool M_Spider_Attack(int attack_type, entity actor, entity targ, .entity weaponentity)
162{
163 Weapon wep = WEP_SPIDER_ATTACK;
164 switch (attack_type)
165 {
167 wep.wr_think(wep, actor, weaponentity, 2);
168 return true;
169
171 if (vdist(actor.enemy.origin - actor.origin, <=, autocvar_g_monster_spider_attack_web_range))
172 {
173 wep.wr_think(wep, actor, weaponentity, 1);
174 return true;
175 }
176 }
177
178 return false;
179}
180
181spawnfunc(monster_spider)
182{
183 Monster_Spawn(this, true, MON_SPIDER);
184}
185
186METHOD(Spider, mr_think, bool(Spider this, entity actor))
187{
188 TC(Spider, this);
189 return true;
190}
191
192METHOD(Spider, mr_pain, float(Spider this, entity actor, float damage_take, entity attacker, float deathtype))
193{
194 TC(Spider, this);
195 setanim(actor, ((random() > 0.5) ? actor.anim_pain2 : actor.anim_pain1), true, true, false);
196 actor.pain_finished = actor.animstate_endtime;
197 return damage_take;
198}
199
200METHOD(Spider, mr_death, bool(Spider this, entity actor))
201{
202 TC(Spider, this);
203 setanim(actor, ((random() > 0.5) ? actor.anim_die2 : actor.anim_die1), false, true, true);
204 return true;
205}
206#endif // SVQC
207#ifdef GAMEQC
208METHOD(Spider, mr_anim, bool(Spider this, entity actor))
209{
210 TC(Spider, this);
211 vector none = '0 0 0';
212 actor.anim_melee = animfixfps(actor, '0 1 5', none); // analyze models and set framerate
213 actor.anim_die1 = animfixfps(actor, '1 1 1', none);
214 actor.anim_die2 = animfixfps(actor, '2 1 1', none);
215 actor.anim_shoot = animfixfps(actor, '3 1 1', none);
216 //actor.anim_fire2 = animfixfps(actor, '4 1 1', none);
217 actor.anim_idle = animfixfps(actor, '5 1 1', none);
218 //actor.anim_sight = animfixfps(actor, '6 1 1', none);
219 actor.anim_pain1 = animfixfps(actor, '7 1 1', none);
220 actor.anim_pain2 = animfixfps(actor, '8 1 1', none);
221 //actor.anim_pain3 = animfixfps(actor, '9 1 1', none);
222 actor.anim_walk = animfixfps(actor, '10 1 1', none);
223 actor.anim_run = animfixfps(actor, '10 1 1', none); // temp?
224 //actor.anim_forwardright = animfixfps(actor, '11 1 1', none);
225 //actor.anim_walkright = animfixfps(actor, '12 1 1', none);
226 //actor.anim_walkbackright = animfixfps(actor, '13 1 1', none);
227 //actor.anim_walkback = animfixfps(actor, '14 1 1', none);
228 //actor.anim_walkbackleft = animfixfps(actor, '15 1 1', none);
229 //actor.anim_walkleft = animfixfps(actor, '16 1 1', none);
230 //actor.anim_forwardleft = animfixfps(actor, '17 1 1', none);
231 return true;
232}
233#endif // GAMEQC
234#ifdef SVQC
235METHOD(Spider, mr_setup, bool(Spider this, entity actor))
236{
237 TC(Spider, this);
238 if (!GetResource(this, RES_HEALTH))
240 if (!actor.speed) actor.speed = autocvar_g_monster_spider_speed_walk;
241 if (!actor.speed2) actor.speed2 = autocvar_g_monster_spider_speed_run;
242 if (!actor.stopspeed) actor.stopspeed = autocvar_g_monster_spider_speed_stop;
243 if (!actor.damageforcescale) actor.damageforcescale = autocvar_g_monster_spider_damageforcescale;
244
245 actor.monster_loot = autocvar_g_monster_spider_loot;
246 actor.monster_attackfunc = M_Spider_Attack;
247
248 return true;
249}
250#endif // SVQC
251#ifdef MENUQC
252METHOD(Spider, describe, string(Spider this))
253{
254 TC(Spider, this);
256 PAR(_("The Spider is a large mechanically-enhanced arachnoid adept at hunting speedy enemies."));
257 PAR(_("To slow down its target, the Spider launches a synthetic web-like substance from its cannons. "
258 "Approaching its enwebbed prey, the Spider will inflict a series of high damage bites."));
259 return PAGE_TEXT;
260}
261#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.
bool SetResourceExplicit(entity e, Resource res_type, float amount)
Sets the resource amount of an entity without calling any hooks.
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:85
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:943
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:120
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define FOREACH_ENTITY_RADIUS(org, dist, cond, body)
Definition iter.qh:160
#define TC(T, sym)
Definition _all.inc:82
#define STAT(...)
Definition stats.qh:82
float random(void)
vector normalize(vector v)
vector animfixfps(entity e, vector a, vector b)
Definition util.qc:1905
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
const int MOVETYPE_BOUNCE
Definition movetypes.qh:139
var void func_null()
#define METHOD(cname, name, prototype)
Definition oo.qh:269
#define NULL
Definition post.qh:14
const int PROJECTILE_ELECTRO
Definition projectiles.qh:3
#define setthink(e, f)
vector
Definition self.qh:92
entity entity toucher
Definition self.qh:72
#define settouch(e, f)
Definition self.qh:73
void adaptor_think2use_hittype_splash(entity this)
Definition common.qc:106
const int MIF_SPLASH
Definition common.qh:46
int projectiledeathtype
Definition common.qh:21
#define PROJECTILE_TOUCH(e, t)
Definition common.qh:28
IntrusiveList g_projectiles
Definition common.qh:58
const int MIF_ARC
Definition common.qh:47
#define PROJECTILE_MAKETRIGGER(e)
Definition common.qh:34
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:96
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:111
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:161
float autocvar_g_monster_spider_speed_stop
Definition spider.qc:16
float autocvar_g_monster_spider_speed_run
Definition spider.qc:17
void M_Spider_Attack_Web(entity this)
Definition spider.qc:123
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:87
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:116
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:642
#define PAR(...)
Adds an individually translatable paragraph to PAGE_TEXT without having to deal with strcat and sprin...
Definition string.qh:648
#define PAGE_TEXT_INIT()
Definition string.qh:641
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:185
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)