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#if defined(SVQC)
5#endif
6
7#ifdef SVQC
9string autocvar_g_monster_spider_loot = "health_medium";
21
23
25
26REGISTER_MUTATOR(spiderweb, true);
27
28MUTATOR_HOOKFUNCTION(spiderweb, PlayerPhysics_UpdateStats)
29{
30 entity player = M_ARGV(0, entity);
31
32 if(StatusEffects_active(STATUSEFFECT_Webbed, player))
33 STAT(MOVEVARS_HIGHSPEED, player) *= 0.5;
34}
35
36MUTATOR_HOOKFUNCTION(spiderweb, MonsterMove)
37{
38 entity mon = M_ARGV(0, entity);
39
40 if(StatusEffects_active(STATUSEFFECT_Webbed, mon))
41 {
42 M_ARGV(1, float) *= 0.5; // run speed
43 M_ARGV(2, float) *= 0.5; // walk speed
44 }
45}
46
47SOUND(SpiderAttack_FIRE, W_Sound("electro_fire2"));
48METHOD(SpiderAttack, wr_think, void(SpiderAttack thiswep, entity actor, .entity weaponentity, int fire))
49{
50 TC(SpiderAttack, thiswep);
51 bool isPlayer = IS_PLAYER(actor);
52 if (fire & 1)
53 if ((!isPlayer && time >= actor.spider_web_delay) || (isPlayer && weapon_prepareattack(thiswep, actor, weaponentity, false, autocvar_g_monster_spider_attack_web_delay))) {
54 if (!isPlayer) {
55 actor.spider_web_delay = time + autocvar_g_monster_spider_attack_web_delay;
56 setanim(actor, actor.anim_shoot, true, true, true);
57 if(actor.animstate_endtime > time)
58 actor.anim_finished = actor.animstate_endtime;
59 else
60 actor.anim_finished = time + 1;
61 actor.attack_finished_single[0] = actor.anim_finished + 0.2;
62 }
63 if (isPlayer) actor.enemy = Monster_FindTarget(actor);
64 monster_makevectors(actor, actor.enemy);
65 W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_SpiderAttack_FIRE, CH_WEAPON_B, 0, DEATH_MONSTER_SPIDER.m_id);
66 if (!isPlayer) w_shotdir = normalize((actor.enemy.origin + '0 0 10') - actor.origin);
68 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
69 return;
70 }
71 if (fire & 2)
72 if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, true, 0.5)) {
73 if (isPlayer) {
74 actor.enemy = Monster_FindTarget(actor);
75 actor.attack_range = 60;
76 }
77 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);
78 weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, 0, w_ready);
79 }
80}
81
83{
84 if(this)
85 {
86 Send_Effect(EFFECT_ELECTRO_IMPACT, this.origin, '0 0 0', 1);
87 RadiusDamage(this, this.realowner, 0, 0, 25, NULL, NULL, 25, this.projectiledeathtype, DMG_NOWEP, NULL);
88
89 FOREACH_ENTITY_RADIUS(this.origin, 25, it != this && it.takedamage && !IS_DEAD(it) && GetResource(it, RES_HEALTH) > 0 && it.monsterdef != MON_SPIDER,
90 {
91 StatusEffects_apply(STATUSEFFECT_Webbed, it, time + autocvar_g_monster_spider_attack_web_damagetime, 0);
92 });
93
94 delete(this);
95 }
96}
97
102
109
111{
112 sound(this, CH_SHOTS, SND_SpiderAttack_FIRE, VOL_BASE, ATTEN_NORM);
113
114 entity proj = new(plasma);
115 proj.owner = proj.realowner = this;
118 proj.bot_dodge = true;
119 proj.bot_dodgerating = 0;
120 proj.nextthink = time + 5;
122 proj.projectiledeathtype = DEATH_MONSTER_SPIDER.m_id;
123 setorigin(proj, CENTER_OR_VIEWOFS(this));
124
125 //proj.glow_size = 50;
126 //proj.glow_color = 45;
130 setsize(proj, '-4 -4 -4', '4 4 4');
131 proj.takedamage = DAMAGE_NO;
132 proj.damageforcescale = 0;
133 SetResourceExplicit(proj, RES_HEALTH, 500);
134 proj.event_damage = func_null;
135 proj.flags = FL_PROJECTILE;
136 IL_PUSH(g_projectiles, proj);
137 IL_PUSH(g_bot_dodge, proj);
138 proj.damagedbycontents = true;
140
141 proj.bouncefactor = 0.3;
142 proj.bouncestop = 0.05;
143 proj.missile_flags = MIF_SPLASH | MIF_ARC;
144
145 CSQCProjectile(proj, true, PROJECTILE_ELECTRO, true);
146}
147
148bool M_Spider_Attack(int attack_type, entity actor, entity targ, .entity weaponentity)
149{
150 Weapon wep = WEP_SPIDER_ATTACK;
151 switch(attack_type)
152 {
154 {
155 wep.wr_think(wep, actor, weaponentity, 2);
156 return true;
157 }
159 {
160 if(vdist(actor.enemy.origin - actor.origin, <=, autocvar_g_monster_spider_attack_web_range))
161 {
162 wep.wr_think(wep, actor, weaponentity, 1);
163 return true;
164 }
165 }
166 }
167
168 return false;
169}
170
171spawnfunc(monster_spider) { Monster_Spawn(this, true, MON_SPIDER); }
172#endif // SVQC
173
174#ifdef SVQC
175METHOD(Spider, mr_think, bool(Spider this, entity actor))
176{
177 TC(Spider, this);
178 return true;
179}
180
181METHOD(Spider, mr_pain, float(Spider this, entity actor, float damage_take, entity attacker, float deathtype))
182{
183 TC(Spider, this);
184 setanim(actor, ((random() > 0.5) ? actor.anim_pain2 : actor.anim_pain1), true, true, false);
185 actor.pain_finished = actor.animstate_endtime;
186 return damage_take;
187}
188
189METHOD(Spider, mr_death, bool(Spider this, entity actor))
190{
191 TC(Spider, this);
192 setanim(actor, ((random() > 0.5) ? actor.anim_die2 : actor.anim_die1), false, true, true);
193 return true;
194}
195#endif
196#ifdef GAMEQC
197METHOD(Spider, mr_anim, bool(Spider this, entity actor))
198{
199 TC(Spider, this);
200 vector none = '0 0 0';
201 actor.anim_melee = animfixfps(actor, '0 1 5', none); // analyze models and set framerate
202 actor.anim_die1 = animfixfps(actor, '1 1 1', none);
203 actor.anim_die2 = animfixfps(actor, '2 1 1', none);
204 actor.anim_shoot = animfixfps(actor, '3 1 1', none);
205 //actor.anim_fire2 = animfixfps(actor, '4 1 1', none);
206 actor.anim_idle = animfixfps(actor, '5 1 1', none);
207 //actor.anim_sight = animfixfps(actor, '6 1 1', none);
208 actor.anim_pain1 = animfixfps(actor, '7 1 1', none);
209 actor.anim_pain2 = animfixfps(actor, '8 1 1', none);
210 //actor.anim_pain3 = animfixfps(actor, '9 1 1', none);
211 actor.anim_walk = animfixfps(actor, '10 1 1', none);
212 actor.anim_run = animfixfps(actor, '10 1 1', none); // temp?
213 //actor.anim_forwardright = animfixfps(actor, '11 1 1', none);
214 //actor.anim_walkright = animfixfps(actor, '12 1 1', none);
215 //actor.anim_walkbackright = animfixfps(actor, '13 1 1', none);
216 //actor.anim_walkback = animfixfps(actor, '14 1 1', none);
217 //actor.anim_walkbackleft = animfixfps(actor, '15 1 1', none);
218 //actor.anim_walkleft = animfixfps(actor, '16 1 1', none);
219 //actor.anim_forwardleft = animfixfps(actor, '17 1 1', none);
220 return true;
221}
222#endif
223#ifdef SVQC
224METHOD(Spider, mr_setup, bool(Spider this, entity actor))
225{
226 TC(Spider, this);
227 if(!GetResource(this, RES_HEALTH)) SetResourceExplicit(actor, RES_HEALTH, autocvar_g_monster_spider_health);
228 if(!actor.speed) { actor.speed = (autocvar_g_monster_spider_speed_walk); }
229 if(!actor.speed2) { actor.speed2 = (autocvar_g_monster_spider_speed_run); }
230 if(!actor.stopspeed) { actor.stopspeed = (autocvar_g_monster_spider_speed_stop); }
231 if(!actor.damageforcescale) { actor.damageforcescale = (autocvar_g_monster_spider_damageforcescale); }
232
233 actor.monster_loot = autocvar_g_monster_spider_loot;
234 actor.monster_attackfunc = M_Spider_Attack;
235
236 return true;
237}
238#endif
239#ifdef MENUQC
240METHOD(Spider, describe, string(Spider this))
241{
242 TC(Spider, this);
244 PAR(_("The Spider is a large mechanically-enhanced arachnoid adept at hunting speedy enemies."));
245 PAR(_("To slow down its target, the Spider launches a synthetic web-like substance from its cannons. "
246 "Approaching its enwebbed prey, the Spider will inflict a series of high damage bites."));
247 return PAGE_TEXT;
248}
249#endif
#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:44
virtual void wr_think()
(SERVER) logic to run every frame
Definition weapon.qh:90
#define M_ARGV(x, type)
Definition events.qh:17
#define IS_DEAD(s)
Definition player.qh:245
#define IS_PLAYER(s)
Definition player.qh:243
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:981
IntrusiveList g_damagedbycontents
Definition damage.qh:135
#define DMG_NOWEP
Definition damage.qh:104
void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt)
Definition all.qc:124
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:1808
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:225
#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:12
float autocvar_g_monster_spider_damageforcescale
Definition spider.qc:10
string autocvar_g_monster_spider_loot
Definition spider.qc:9
void M_Spider_Attack_Web_Explode_use(entity this, entity actor, entity trigger)
Definition spider.qc:98
float autocvar_g_monster_spider_attack_web_delay
Definition spider.qc:16
float autocvar_g_monster_spider_attack_web_speed
Definition spider.qc:14
bool M_Spider_Attack(int attack_type, entity actor, entity targ,.entity weaponentity)
Definition spider.qc:148
float autocvar_g_monster_spider_speed_stop
Definition spider.qc:18
float autocvar_g_monster_spider_speed_run
Definition spider.qc:19
void M_Spider_Attack_Web(entity this)
Definition spider.qc:110
float spider_web_delay
Definition spider.qc:22
float autocvar_g_monster_spider_speed_walk
Definition spider.qc:20
float autocvar_g_monster_spider_health
Definition spider.qc:8
void M_Spider_Attack_Web_Explode(entity this)
Definition spider.qc:82
float autocvar_g_monster_spider_attack_web_range
Definition spider.qc:17
void M_Spider_Attack_Web_Touch(entity this, entity toucher)
Definition spider.qc:103
float autocvar_g_monster_spider_attack_bite_damage
Definition spider.qc:11
float autocvar_g_monster_spider_attack_web_damagetime
Definition spider.qc:13
float autocvar_g_monster_spider_attack_web_speed_up
Definition spider.qc:15
bool StatusEffects_active(StatusEffect this, entity actor)
#define PAGE_TEXT
Definition string.qh:643
#define PAR(...)
Adds an individually translatable paragraph to PAGE_TEXT without having to deal with strcat and sprin...
Definition string.qh:649
#define PAGE_TEXT_INIT()
Definition string.qh:642
const int DAMAGE_NO
Definition subs.qh:79
bool Monster_Spawn(entity this, bool check_appear, Monster mon)
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:192
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:29
#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)