Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
minelayer.qc
Go to the documentation of this file.
1#include "minelayer.qh"
2
3#ifdef SVQC
4
6{
7 spamsound(this, CH_SHOTS, SND_MINE_STICK, VOL_BASE, ATTN_NORM);
8
9 // in order for mines to face properly when sticking to the ground, they must be a server side entity rather than a csqc projectile
10
11 entity newmine = spawn();
12 IL_PUSH(g_mines, newmine);
13 newmine.weaponentity_fld = this.weaponentity_fld;
14 newmine.classname = this.classname;
15
16 newmine.bot_dodge = this.bot_dodge;
17 newmine.bot_dodgerating = this.bot_dodgerating;
18
19 newmine.owner = this.owner;
20 newmine.realowner = this.realowner;
21 newmine.glowmod = colormapPaletteColor(this.realowner.clientcolors & 0x0F, true);
22
24 setorigin(newmine, this.origin);
25 setmodel(newmine, MDL_MINELAYER_MINE);
26 setsize(newmine, '-4 -4 -4', '4 4 4');
27 newmine.angles = vectoangles(-trace_plane_normal); // face against the surface
28
29 newmine.movedir = -trace_plane_normal;
30
31 newmine.takedamage = this.takedamage;
32 newmine.damageforcescale = this.damageforcescale;
33 SetResourceExplicit(newmine, RES_HEALTH, GetResource(this, RES_HEALTH));
34 newmine.event_damage = this.event_damage;
35 newmine.spawnshieldtime = this.spawnshieldtime;
36 newmine.damagedbycontents = true;
38
39 set_movetype(newmine, MOVETYPE_NONE); // lock the mine in place
40 newmine.projectiledeathtype = this.projectiledeathtype;
41
42 newmine.mine_time = this.mine_time;
43
44 settouch(newmine, func_null);
46 newmine.nextthink = time;
47 newmine.cnt = this.cnt;
48 newmine.flags = this.flags;
49 IL_PUSH(g_projectiles, newmine);
50 IL_PUSH(g_bot_dodge, newmine);
51
52 delete(this);
53
54 if(to)
55 SetMovetypeFollow(newmine, to);
56}
57
58void W_MineLayer_Explode(entity this, entity directhitentity)
59{
60 if(directhitentity.takedamage == DAMAGE_AIM)
61 if(IS_PLAYER(directhitentity))
62 if(DIFF_TEAM(this.realowner, directhitentity))
63 if(!IS_DEAD(directhitentity))
64 if(IsFlying(directhitentity))
65 Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
66
67 this.event_damage = func_null;
68 this.takedamage = DAMAGE_NO;
69
70 RadiusDamage(this, this.realowner, WEP_CVAR(WEP_MINE_LAYER, damage), WEP_CVAR(WEP_MINE_LAYER, edgedamage), WEP_CVAR(WEP_MINE_LAYER, radius), NULL, NULL, WEP_CVAR(WEP_MINE_LAYER, force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
71
72 .entity weaponentity = this.weaponentity_fld;
73 Weapon thiswep = WEP_MINE_LAYER;
74 if(this.realowner.(weaponentity).m_weapon == thiswep)
75 {
76 entity own = this.realowner;
77 if(!thiswep.wr_checkammo1(thiswep, own, weaponentity))
78 if(!(own.items & IT_UNLIMITED_AMMO))
79 {
80 own.cnt = thiswep.m_id;
81 ATTACK_FINISHED(own, weaponentity) = time;
82 own.(weaponentity).m_switchweapon = w_getbestweapon(own, weaponentity);
83 }
84 }
85 delete(this);
86}
87
92
94{
95 this.event_damage = func_null;
96 this.takedamage = DAMAGE_NO;
97
99 this.velocity = this.movedir; // .velocity must be != '0 0 0' for particle fx and decal to work
100
101 RadiusDamage(this, this.realowner, WEP_CVAR(WEP_MINE_LAYER, remote_damage), WEP_CVAR(WEP_MINE_LAYER, remote_edgedamage), WEP_CVAR(WEP_MINE_LAYER, remote_radius),
102 NULL, NULL, WEP_CVAR(WEP_MINE_LAYER, remote_force), this.projectiledeathtype | HITTYPE_BOUNCE, this.weaponentity_fld, NULL);
103
104 .entity weaponentity = this.weaponentity_fld;
105 Weapon thiswep = WEP_MINE_LAYER;
106 if(this.realowner.(weaponentity).m_weapon == thiswep)
107 {
108 entity own = this.realowner;
109 if(!thiswep.wr_checkammo1(thiswep, own, weaponentity))
110 if(!(own.items & IT_UNLIMITED_AMMO))
111 {
112 own.cnt = thiswep.m_id;
113 ATTACK_FINISHED(own, weaponentity) = time;
114 own.(weaponentity).m_switchweapon = w_getbestweapon(own, weaponentity);
115 }
116 }
117 delete(this);
118}
119
121{
122 if(IS_DEAD(this.realowner))
123 return;
124
125 if(this.spawnshieldtime >= 0)
126 {
127 if(time < this.spawnshieldtime) // timer
128 return;
129 }
130 else
131 {
132 /* make sure no friend is in the mine's radius.
133 * WEAPONTODO: modify protection cvar to allow disabling remote detonation protection.
134 * disabling it currently allows Mine Layer-flying, even more powerful than rocket-flying
135 * ... even without Rocket Flying mutator enabled
136 */
137 entity head = WarpZone_FindRadius(this.origin, WEP_CVAR(WEP_MINE_LAYER, remote_radius), false);
138 while(head)
139 {
140 if(SAME_TEAM(head, this.realowner))
141 return;
142 head = head.chain;
143 }
144 }
145
147}
148
150{
151 // make sure no friend is in the mine's radius. If there is any, explosion is delayed until they're at a safe distance
152 if(WEP_CVAR(WEP_MINE_LAYER, protection) && this.mine_explodeanyway == 0)
153 {
154 entity head = WarpZone_FindRadius(this.origin, WEP_CVAR(WEP_MINE_LAYER, radius), false);
155 while(head)
156 {
157 if(SAME_TEAM(head, this.realowner))
158 return;
159 head = head.chain;
160 }
161 }
162
163 this.mine_time = 0;
165}
166
167int W_MineLayer_Count(entity e, .entity weaponentity)
168{
169 int minecount = 0;
170 IL_EACH(g_mines, it.realowner == e && it.weaponentity_fld == weaponentity,
171 {
172 minecount += 1;
173 });
174
175 return minecount;
176}
177
179{
180 entity head;
181
182 this.nextthink = time;
183
185 {
186 if(LostMovetypeFollow(this))
187 {
190 }
191 }
192
193 // our lifetime has expired, it's time to die - mine_time just allows us to play a sound for this
194 // TODO: replace this mine_trigger.wav sound with a real countdown
195 if((time > this.cnt) && (!this.mine_time) && (this.cnt > 0))
196 {
197 if(WEP_CVAR(WEP_MINE_LAYER, lifetime_countdown) > 0)
198 spamsound(this, CH_SHOTS, SND_MINE_TRIGGER, VOL_BASE, ATTN_NORM);
199 this.mine_time = time + WEP_CVAR(WEP_MINE_LAYER, lifetime_countdown);
200 this.mine_explodeanyway = 1; // make the mine super aggressive -- Samual: Rather, make it not care if a teammate is near.
201 }
202
203 // a player's mines shall explode if they disconnect or die
204 if(!IS_PLAYER(this.realowner) || IS_DEAD(this.realowner) || STAT(FROZEN, this.realowner))
205 {
208 return;
209 }
210
211 // set the mine for detonation when a foe gets close enough
212 float time_core = WEP_CVAR(WEP_MINE_LAYER, proximity_time_core);
213 float time_edge = WEP_CVAR(WEP_MINE_LAYER, proximity_time_edge);
214 float proxrad = WEP_CVAR(WEP_MINE_LAYER, proximity_radius);
215 head = WarpZone_FindRadius(this.origin, proxrad, false);
216 while(head)
217 {
218 if(IS_PLAYER(head) && !IS_DEAD(head) && !STAT(FROZEN, head) && !IS_INDEPENDENT_PLAYER(head))
219 if(DIFF_TEAM(head, this.realowner)) // don't trigger for teammates
220 {
221 if(!this.mine_time) // don't repeat the sound
222 spamsound(this, CH_SHOTS, SND_MINE_TRIGGER, VOL_BASE, ATTN_NORM);
223 // scale from time_edge to time_core based on how close the player is to the mine
224 float new_mine_time = time + time_core;
225 if(time_edge != time_core)
226 new_mine_time += (time_edge - time_core) * vlen(head.WarpZone_findradius_dist) / proxrad;
227 if((!this.mine_time) || this.mine_time > new_mine_time) // choose the earliest explosion time
228 this.mine_time = new_mine_time;
229 }
230 head = head.chain;
231 }
232
233 // explode if it's time to
234 if(this.mine_time && time >= this.mine_time)
235 {
237 return;
238 }
239
240 // remote detonation
241 .entity weaponentity = this.weaponentity_fld;
242 if(this.realowner.(weaponentity).m_weapon == WEP_MINE_LAYER)
243 if(!IS_DEAD(this.realowner))
244 if(this.minelayer_detonate)
245 {
247 return;
248 }
249
250 // if it was detached by damage but landed during the bounce time, reenable gravity so it will touch and reattach
251 if (this.move_movetype == MOVETYPE_BOUNCE && IS_ONGROUND(this))
252 UNSET_ONGROUND(this);
253}
254
256{
258 return; // we're already a stuck mine, why do we get called? TODO does this even happen?
259 if(time <= this.wait)
260 return; // don't reattach yet
261
263
264 if (toucher.solid == SOLID_BSP)
266}
267
268void W_MineLayer_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
269{
270 if(GetResource(this, RES_HEALTH) <= 0)
271 return;
272
273 // Reading the cvar here because this.damageforcescale is overridden in blaster.qc
274 // this way the blaster can hit mines midair but can only detach them when enabled by this cvar.
275 if (WEP_CVAR(WEP_MINE_LAYER, damageforcescale) && inflictor.classname != "mine")
276 {
277 set_movetype(this, MOVETYPE_BOUNCE); // not TOSS: so a direct perpendicular hit can move the mine
278 this.wait = time + 0.0625; // after this time it will reattach instead of bouncing
280 this.avelocity += force * -WEP_CVAR(WEP_MINE_LAYER, damageforcescale);
281 }
282
283 float is_from_enemy = (inflictor.realowner != this.realowner);
284
285 if(!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, (is_from_enemy ? 1 : -1)))
286 return; // g_projectiles_damage says to halt
287
288 TakeResource(this, RES_HEALTH, damage);
289 this.angles = vectoangles(this.velocity);
290
291 if(GetResource(this, RES_HEALTH) <= 0)
293}
294
295void W_MineLayer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
296{
297 // scan how many mines we placed, and return if we reached our limit
298 if(WEP_CVAR(WEP_MINE_LAYER, limit))
299 {
300 int minecount = W_MineLayer_Count(actor, weaponentity);
301 if(minecount >= WEP_CVAR(WEP_MINE_LAYER, limit))
302 {
303 // the refire delay keeps this message from being spammed
304 Send_Notification(NOTIF_ONE, actor, MSG_MULTI, WEAPON_MINELAYER_LIMIT, WEP_CVAR(WEP_MINE_LAYER, limit));
305 play2(actor, SND(UNAVAILABLE));
306 return;
307 }
308 }
309
310 W_DecreaseAmmo(thiswep, actor, WEP_CVAR(WEP_MINE_LAYER, ammo), weaponentity);
311
312 W_SetupShot_ProjectileSize(actor, weaponentity, '-4 -4 -4', '4 4 4', false, 5, SND_MINE_FIRE, CH_WEAPON_A, WEP_CVAR(WEP_MINE_LAYER, damage), thiswep.m_id);
313 W_MuzzleFlash(thiswep, actor, weaponentity, w_shotorg, w_shotdir);
314
316 mine.weaponentity_fld = weaponentity;
317 IL_PUSH(g_mines, mine);
318 mine.owner = mine.realowner = actor;
319 if(WEP_CVAR(WEP_MINE_LAYER, detonatedelay) >= 0)
320 mine.spawnshieldtime = time + WEP_CVAR(WEP_MINE_LAYER, detonatedelay);
321 else
322 mine.spawnshieldtime = -1;
323 mine.classname = "mine";
324 mine.bot_dodge = true;
325 mine.bot_dodgerating = WEP_CVAR(WEP_MINE_LAYER, damage) * 2; // * 2 because it can detonate inflight which makes it even more dangerous
326
327 mine.takedamage = DAMAGE_YES;
328 mine.damageforcescale = WEP_CVAR(WEP_MINE_LAYER, damageforcescale);
329 SetResourceExplicit(mine, RES_HEALTH, WEP_CVAR(WEP_MINE_LAYER, health));
330 mine.event_damage = W_MineLayer_Damage;
331 mine.damagedbycontents = true;
333
336 mine.projectiledeathtype = thiswep.m_id;
337 mine.weaponentity_fld = weaponentity;
338 setsize(mine, '-4 -4 -4', '4 4 4'); // give it some size so it can be shot
339
340 setorigin(mine, w_shotorg - v_forward * 4); // move it back so it hits the wall at the right point
341 W_SetupProjVelocity_Basic(mine, WEP_CVAR(WEP_MINE_LAYER, speed), 0);
342 mine.angles = vectoangles(mine.velocity);
343
346 mine.nextthink = time;
347 mine.cnt = (WEP_CVAR(WEP_MINE_LAYER, lifetime) - WEP_CVAR(WEP_MINE_LAYER, lifetime_countdown));
348 mine.flags = FL_PROJECTILE;
349 IL_PUSH(g_projectiles, mine);
350 IL_PUSH(g_bot_dodge, mine);
351 mine.missile_flags = MIF_SPLASH | MIF_ARC | MIF_PROXY;
352
353 if(mine.cnt > 0) { mine.cnt += time; }
354
355 CSQCProjectile(mine, true, PROJECTILE_MINE, true);
356
357 // common properties
358
359 MUTATOR_CALLHOOK(EditProjectile, actor, mine);
360}
361
362bool W_MineLayer_PlacedMines(entity this, .entity weaponentity, bool detonate)
363{
364 bool minfound = false;
365
366 IL_EACH(g_mines, it.realowner == this && it.weaponentity_fld == weaponentity,
367 {
368 if(detonate)
369 {
370 if(!it.minelayer_detonate)
371 {
372 it.minelayer_detonate = true;
373 minfound = true;
374 }
375 }
376 else
377 minfound = true;
378 });
379 return minfound;
380}
381
382METHOD(MineLayer, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
383{
384 // aim and decide to fire if appropriate
385 int minecount = W_MineLayer_Count(actor, weaponentity);
386 if(minecount >= WEP_CVAR(WEP_MINE_LAYER, limit))
387 PHYS_INPUT_BUTTON_ATCK(actor) = false;
388 else
389 PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(WEP_MINE_LAYER, speed), 0, WEP_CVAR(WEP_MINE_LAYER, lifetime), false, false);
390 if(skill >= 2) // skill 0 and 1 bots won't detonate mines!
391 {
392 // decide whether to detonate mines
393 float edgedamage, coredamage, edgeradius, recipricoledgeradius;
394 float selfdamage, teamdamage, enemydamage;
395 edgedamage = WEP_CVAR(WEP_MINE_LAYER, edgedamage);
396 coredamage = WEP_CVAR(WEP_MINE_LAYER, damage);
397 edgeradius = WEP_CVAR(WEP_MINE_LAYER, radius);
398 recipricoledgeradius = 1 / edgeradius;
399 selfdamage = 0;
400 teamdamage = 0;
401 enemydamage = 0;
402
403 IL_EACH(g_mines, it.realowner == actor,
404 {
405 entity mine = it;
406 IL_EACH(g_bot_targets, it.bot_attack,
407 {
408 float d = vlen(it.origin + (it.mins + it.maxs) * 0.5 - mine.origin);
409 d = bound(0, edgedamage + (coredamage - edgedamage) * sqrt(1 - d * recipricoledgeradius), 10000);
410 // count potential damage according to type of target
411 if(it == actor)
412 selfdamage = selfdamage + d;
413 else if(SAME_TEAM(it, actor))
414 teamdamage = teamdamage + d;
415 else if(bot_shouldattack(actor, it))
416 enemydamage = enemydamage + d;
417 });
418 });
419
420 float desirabledamage;
421 desirabledamage = enemydamage;
422 if(StatusEffects_active(STATUSEFFECT_Shield, actor) && !StatusEffects_active(STATUSEFFECT_SpawnShield, actor))
423 desirabledamage = desirabledamage - selfdamage * autocvar_g_balance_selfdamagepercent;
424 if(teamplay && actor.team)
425 desirabledamage = desirabledamage - teamdamage;
426
427 makevectors(actor.v_angle);
428 IL_EACH(g_mines, it.realowner == actor,
429 {
430 if(skill > 9) // normal players only do this for the target they are tracking
431 {
432 entity mine = it;
433 IL_EACH(g_bot_targets, it.bot_attack,
434 {
435 if((v_forward * normalize(mine.origin - it.origin) < 0.1)
436 && desirabledamage > 0.1 * coredamage
437 ) PHYS_INPUT_BUTTON_ATCK2(actor) = true;
438 });
439 }
440 else
441 {
442 //As the distance gets larger, a correct detonation gets near imposible
443 //Bots are assumed to use the mine spawnfunc_light to see if the mine gets near a player
444 if((v_forward * normalize(it.origin - actor.enemy.origin) < 0.1)
445 && IS_PLAYER(actor.enemy)
446 && (desirabledamage >= 0.1 * coredamage)
447 )
448 {
449 float distance = bound(300, vlen(actor.origin - actor.enemy.origin), 30000);
450 if(random() / distance * 300 > frametime * bound(0, (10 - skill) * 0.2, 1))
451 PHYS_INPUT_BUTTON_ATCK2(actor) = true;
452 }
453 }
454 });
455
456 // if we would be doing at X percent of the core damage, detonate it
457 // but don't fire a new shot at the same time!
458 if(desirabledamage >= 0.75 * coredamage) //this should do group damage in rare fortunate events
459 PHYS_INPUT_BUTTON_ATCK2(actor) = true;
460 if((skill > 6.5) && (selfdamage > GetResource(actor, RES_HEALTH)))
461 PHYS_INPUT_BUTTON_ATCK2(actor) = false;
462 //if(PHYS_INPUT_BUTTON_ATCK2(actor) == true)
463 // dprint(ftos(desirabledamage),"\n");
464 if(PHYS_INPUT_BUTTON_ATCK2(actor)) PHYS_INPUT_BUTTON_ATCK(actor) = false;
465 }
466}
467
468METHOD(MineLayer, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
469{
470 actor.(weaponentity).minelayer_mines = W_MineLayer_Count(actor, weaponentity);
471
472 if(autocvar_g_balance_minelayer_reload_ammo && actor.(weaponentity).clip_load < WEP_CVAR(WEP_MINE_LAYER, ammo)) // forced reload
473 {
474 // not if we're holding the minelayer without enough ammo, but can detonate existing mines
475 bool enough_ammo = (GetResource(actor, thiswep.ammo_type) >= WEP_CVAR(WEP_MINE_LAYER, ammo));
476 if(actor.items & IT_UNLIMITED_AMMO)
477 enough_ammo = true;
478 if(!(W_MineLayer_PlacedMines(actor, weaponentity, false) && !enough_ammo)) {
479 thiswep.wr_reload(thiswep, actor, weaponentity);
480 }
481 }
482 else if(fire & 1)
483 {
484 if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(WEP_MINE_LAYER, refire)))
485 {
486 W_MineLayer_Attack(thiswep, actor, weaponentity);
487 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(WEP_MINE_LAYER, animtime), w_ready);
488 }
489 }
490
491 if(fire & 2)
492 {
493 if(W_MineLayer_PlacedMines(actor, weaponentity, true))
494 sound(actor, CH_WEAPON_B, SND_MINE_DET, VOL_BASE, ATTN_NORM);
495 }
496}
497
498METHOD(MineLayer, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
499{
500 // actually do // don't switch while placing a mine
501 //if(ATTACK_FINISHED(actor, weaponentity) <= time || PS(actor).m_weapon != WEP_MINE_LAYER)
502 //{
503 float ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR(WEP_MINE_LAYER, ammo);
504 ammo_amount += actor.(weaponentity).(weapon_load[thiswep.m_id]) >= WEP_CVAR(WEP_MINE_LAYER, ammo);
505 return ammo_amount;
506 //}
507 //return true;
508}
509
510METHOD(MineLayer, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
511{
512 if(W_MineLayer_PlacedMines(actor, weaponentity, false))
513 return true;
514 else
515 return false;
516}
517
518METHOD(MineLayer, wr_resetplayer, void(entity thiswep, entity actor))
519{
520 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
521 {
522 .entity weaponentity = weaponentities[slot];
523 actor.(weaponentity).minelayer_mines = 0;
524 }
525}
526
527METHOD(MineLayer, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
528{
529 W_Reload(actor, weaponentity, WEP_CVAR(WEP_MINE_LAYER, ammo), SND_RELOAD);
530}
531
532METHOD(MineLayer, wr_suicidemessage, Notification(entity thiswep))
533{
534 return WEAPON_MINELAYER_SUICIDE;
535}
536
537METHOD(MineLayer, wr_killmessage, Notification(entity thiswep))
538{
539 return WEAPON_MINELAYER_MURDER;
540}
541
542#endif
543#ifdef CSQC
544
545METHOD(MineLayer, wr_impacteffect, void(entity thiswep, entity actor))
546{
547 vector org2 = w_org + w_backoff * 2;
548 pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
549 if(!w_issilent)
550 sound(actor, CH_SHOTS, SND_MINE_EXP, VOL_BASE, ATTN_NORM);
551}
552
553#endif
554#ifdef MENUQC
559
560METHOD(MineLayer, describe, string(MineLayer this))
561{
562 TC(MineLayer, this);
564 PAR(_("The %s places mines on the ground when fired, which detonate and damage enemies if stepped on. "
565 "Only a couple mines can be placed at any time, and after several seconds they will self-detonate."), COLORED_NAME(this));
566 PAR(_("The secondary fire instantaneously detonates any mines fired by the primary fire, first waiting until you're far enough away."));
567 PAR(_("It consumes %s ammo for each mine laid."), COLORED_NAME(ITEM_Rockets));
568 PAR(_("The mines are not launched very far before they hit the ground, so the %s isn't very effective at medium to long ranges. "
569 "It is often used to protect important areas of the map such as the flag in %s, control points in %s, or checkpoints in %s."), COLORED_NAME(this), COLORED_NAME(MAPINFO_TYPE_CTF), COLORED_NAME(MAPINFO_TYPE_ONSLAUGHT), COLORED_NAME(MAPINFO_TYPE_ASSAULT));
570 PAR(W_Guide_Keybinds(this));
572 return PAGE_TEXT;
573}
574
575#endif
float bot_dodge
Definition api.qh:40
float skill
Definition api.qh:35
float bot_dodgerating
Definition api.qh:39
bool bot_aim(entity this,.entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity, bool shot_accurate)
IntrusiveList g_bot_dodge
Definition api.qh:150
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
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.
void TakeResource(entity receiver, Resource res_type, float amount)
Takes an entity some resource.
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
int m_id
Definition weapon.qh:45
virtual void wr_checkammo1()
(SERVER) checks ammo for weapon primary
Definition weapon.qh:92
string netname
Definition powerups.qc:20
float lifetime
Definition powerups.qc:23
float cnt
Definition powerups.qc:24
float wait
Definition items.qc:17
entity owner
Definition main.qh:87
#define colormapPaletteColor(c, isPants)
Definition color.qh:5
#define COLORED_NAME(this)
Definition color.qh:195
const int IT_UNLIMITED_AMMO
Definition item.qh:23
float radius
Definition impulse.qh:11
#define setmodel(this, m)
Definition model.qh:26
bool IsFlying(entity this)
Definition player.qc:836
#define IS_DEAD(s)
Definition player.qh:245
#define IS_PLAYER(s)
Definition player.qh:243
#define PHYS_INPUT_BUTTON_ATCK(s)
Definition player.qh:150
#define PHYS_INPUT_BUTTON_ATCK2(s)
Definition player.qh:152
void SetMovetypeFollow(entity ent, entity e)
Definition util.qc:2033
void UnsetMovetypeFollow(entity ent)
Definition util.qc:2053
int LostMovetypeFollow(entity ent)
Definition util.qc:2063
const int FL_PROJECTILE
Definition constants.qh:85
string classname
float flags
vector avelocity
vector velocity
float time
float nextthink
vector v_forward
vector origin
const float ATTN_NORM
const float SOLID_BSP
vector trace_plane_normal
#define spawn
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
float spawnshieldtime
Definition damage.qh:61
float autocvar_g_balance_selfdamagepercent
Definition damage.qh:25
vector w_org
float damageforcescale
vector w_backoff
float w_issilent
const int HITTYPE_BOUNCE
Definition all.qh:31
float speed
Definition dynlight.qc:9
#define pointparticles(effect, org, vel, howmany)
Definition effect.qh:7
ent angles
Definition ent_cs.qc:121
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define IL_EACH(this, cond, body)
#define TC(T, sym)
Definition _all.inc:82
#define STAT(...)
Definition stats.qh:82
entity WarpZone_FindRadius(vector org, float rad, bool needlineofsight)
Definition common.qc:686
entity WarpZone_RefSys_SpawnSameRefSys(entity me)
Definition common.qc:808
vector movedir
Definition viewloc.qh:18
float vlen(vector v)
vector vectoangles(vector v)
void W_MineLayer_ProximityExplode(entity this)
Definition minelayer.qc:149
void W_MineLayer_Explode_think(entity this)
Definition minelayer.qc:88
void W_MineLayer_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition minelayer.qc:268
int W_MineLayer_Count(entity e,.entity weaponentity)
Definition minelayer.qc:167
void W_MineLayer_Explode(entity this, entity directhitentity)
Definition minelayer.qc:58
void W_MineLayer_Stick(entity this, entity to)
Definition minelayer.qc:5
void W_MineLayer_Think(entity this)
Definition minelayer.qc:178
bool W_MineLayer_PlacedMines(entity this,.entity weaponentity, bool detonate)
Definition minelayer.qc:362
void W_MineLayer_Attack(Weapon thiswep, entity actor,.entity weaponentity)
Definition minelayer.qc:295
void W_MineLayer_Touch(entity this, entity toucher)
Definition minelayer.qc:255
void W_MineLayer_DoRemoteExplode(entity this)
Definition minelayer.qc:93
void W_MineLayer_RemoteExplode(entity this)
Definition minelayer.qc:120
IntrusiveList g_mines
Definition minelayer.qh:83
float minelayer_detonate
Definition minelayer.qh:80
float mine_explodeanyway
Definition minelayer.qh:80
float mine_time
Definition minelayer.qh:81
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
const int MOVETYPE_NONE
Definition movetypes.qh:129
const int MOVETYPE_FOLLOW
Definition movetypes.qh:141
float move_movetype
Definition movetypes.qh:76
#define UNSET_ONGROUND(s)
Definition movetypes.qh:18
const int MOVETYPE_TOSS
Definition movetypes.qh:135
const int MOVETYPE_BOUNCE
Definition movetypes.qh:139
#define IS_ONGROUND(s)
Definition movetypes.qh:16
var void func_null()
void Send_Notification(NOTIF broadcast, entity client, MSG net_type, Notification net_name,...count)
Definition all.qc:1573
entity Notification
always last
Definition all.qh:81
#define METHOD(cname, name, prototype)
Definition oo.qh:269
#define NULL
Definition post.qh:14
#define makevectors
Definition post.qh:21
const int PROJECTILE_MINE
float health
Legacy fields for the resources. To be removed.
Definition resources.qh:9
#define w_getbestweapon(ent, wepent)
Definition selection.qh:23
#define setthink(e, f)
vector
Definition self.qh:92
entity entity toucher
Definition self.qh:72
#define settouch(e, f)
Definition self.qh:73
#define IS_INDEPENDENT_PLAYER(e)
Definition client.qh:312
float W_CheckProjectileDamage(entity inflictor, entity projowner, int deathtype, float exception)
Definition common.qc:45
void W_PrepareExplosionByDamage(entity this, entity attacker, void(entity this) explode)
Definition common.qc:87
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_PROXY
Definition common.qh:48
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 int CH_WEAPON_A
Definition sound.qh:7
#define sound(e, c, s, v, a)
Definition sound.qh:52
const int CH_WEAPON_B
Definition sound.qh:8
void play2(entity e, string filename)
Definition all.qc:116
float spamsound(entity e, int chan, Sound samp, float vol, float _atten)
use this one if you might be causing spam (e.g.
Definition all.qc:124
#define SND(id)
Definition all.qh:35
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_YES
Definition subs.qh:80
const int DAMAGE_NO
Definition subs.qh:79
const int DAMAGE_AIM
Definition subs.qh:81
float takedamage
Definition subs.qh:78
float ammo
Definition sv_turrets.qh:43
#define SAME_TEAM(a, b)
Definition teams.qh:241
bool teamplay
Definition teams.qh:59
#define DIFF_TEAM(a, b)
Definition teams.qh:242
entity realowner
vector w_shotdir
Definition tracing.qh:20
#define W_SetupShot_ProjectileSize(ent, wepent, mi, ma, antilag, recoil, snd, chan, maxdamage, deathtype)
Definition tracing.qh:30
vector w_shotorg
Definition tracing.qh:19
#define W_SetupProjVelocity_Basic(ent, pspeed, pspread)
Definition tracing.qh:49
string W_Guide_Keybinds(Weapon wep)
Definition all.qc:836
void W_MuzzleFlash(Weapon thiswep, entity actor,.entity weaponentity, vector shotorg, vector shotdir)
Definition all.qc:728
string W_Guide_DPS_onlyOne_unnamed(string name)
Definition all.qc:913
#define WEP_CVAR(wep, name)
Definition all.qh:321
const int MAX_WEAPONSLOTS
Definition weapon.qh:16
entity weaponentities[MAX_WEAPONSLOTS]
Definition weapon.qh:17
void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use,.entity weaponentity)
void W_Reload(entity actor,.entity weaponentity, float sent_ammo_min, Sound sent_sound)
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)
#define ATTACK_FINISHED(ent, w)
entity weaponentity_fld
float weapon_load[REGISTRY_MAX(Weapons)]
Weapon m_switchweapon
Definition wepent.qh:25
int minelayer_mines
Definition wepent.qh:11