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 && IS_PLAYER(directhitentity) && DIFF_TEAM(this.realowner, directhitentity) && !IS_DEAD(directhitentity)
62 && IsFlying(directhitentity))
63 Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
64
65 this.event_damage = func_null;
66 this.takedamage = DAMAGE_NO;
67
68 RadiusDamage(this, this.realowner,
69 WEP_CVAR(WEP_MINE_LAYER, damage),
70 WEP_CVAR(WEP_MINE_LAYER, edgedamage),
71 WEP_CVAR(WEP_MINE_LAYER, radius),
72 NULL,
73 NULL,
74 WEP_CVAR(WEP_MINE_LAYER, force),
77 directhitentity
78 );
79
80 .entity weaponentity = this.weaponentity_fld;
81 Weapon thiswep = WEP_MINE_LAYER;
82 if (this.realowner.(weaponentity).m_weapon == thiswep)
83 {
84 entity own = this.realowner;
85 if (!thiswep.wr_checkammo1(thiswep, own, weaponentity)
86 && !(own.items & IT_UNLIMITED_AMMO))
87 {
88 own.cnt = thiswep.m_id;
89 ATTACK_FINISHED(own, weaponentity) = time;
90 own.(weaponentity).m_switchweapon = w_getbestweapon(own, weaponentity);
91 }
92 }
93 delete(this);
94}
95
100
102{
103 this.event_damage = func_null;
104 this.takedamage = DAMAGE_NO;
105
106 if (this.move_movetype == MOVETYPE_NONE
108 this.velocity = this.movedir; // .velocity must be != '0 0 0' for particle fx and decal to work
109
110 RadiusDamage(this, this.realowner,
111 WEP_CVAR(WEP_MINE_LAYER, remote_damage),
112 WEP_CVAR(WEP_MINE_LAYER, remote_edgedamage),
113 WEP_CVAR(WEP_MINE_LAYER, remote_radius),
114 NULL,
115 NULL,
116 WEP_CVAR(WEP_MINE_LAYER, remote_force),
118 this.weaponentity_fld,
119 NULL
120 );
121
122 .entity weaponentity = this.weaponentity_fld;
123 Weapon thiswep = WEP_MINE_LAYER;
124 if (this.realowner.(weaponentity).m_weapon == thiswep)
125 {
126 entity own = this.realowner;
127 if (!thiswep.wr_checkammo1(thiswep, own, weaponentity)
128 && !(own.items & IT_UNLIMITED_AMMO))
129 {
130 own.cnt = thiswep.m_id;
131 ATTACK_FINISHED(own, weaponentity) = time;
132 own.(weaponentity).m_switchweapon = w_getbestweapon(own, weaponentity);
133 }
134 }
135 delete(this);
136}
137
143{
144 if (IS_DEAD(this.realowner))
145 return;
146 if (this.spawnshieldtime >= 0)
147 {
148 if (time < this.spawnshieldtime) // timer
149 return;
150 }
151 else
152 {
153 /* make sure no friend is in the mine's radius.
154 * WEAPONTODO: modify protection cvar to allow disabling remote detonation protection.
155 * disabling it currently allows Mine Layer-flying, even more powerful than rocket-flying
156 * ... even without Rocket Flying mutator enabled
157 */
159 entity head = WarpZone_SearchInRadius(this.origin, WEP_CVAR(WEP_MINE_LAYER, remote_radius), MOVE_NOTHING, W_MineLayer_CheckSameTeam_cond);
160 for (; head; head = head.chain)
161 return;
162 }
163
165}
166
168{
169 // make sure no friend is in the mine's radius. If there is any, explosion is delayed until they're at a safe distance
170 if (WEP_CVAR(WEP_MINE_LAYER, protection) && this.mine_explodeanyway == 0)
171 {
174 for (; head; head = head.chain)
175 return;
176 }
177
178 this.mine_time = 0;
180}
181
182int W_MineLayer_Count(entity e, .entity weaponentity)
183{
184 int minecount = 0;
185 IL_EACH(g_mines, it.realowner == e && it.weaponentity_fld == weaponentity, ++minecount);
186 return minecount;
187}
188
190{
191 return (IS_PLAYER(e) && !IS_DEAD(e) && !STAT(FROZEN, e) && !IS_INDEPENDENT_PLAYER(e)
192 && DIFF_TEAM(e, WarpZone_SearchInRadius_otherent)); // don't trigger for team mates
193}
195{
196 this.nextthink = time;
197
199 {
202 }
203
204 // our lifetime has expired, it's time to die - mine_time just allows us to play a sound for this
205 // WEAPONTODO: replace this mine_trigger.wav sound with a real countdown
206 if (time > this.cnt && !this.mine_time && this.cnt > 0)
207 {
208 if (WEP_CVAR(WEP_MINE_LAYER, lifetime_countdown) > 0)
209 spamsound(this, CH_SHOTS, SND_MINE_TRIGGER, VOL_BASE, ATTN_NORM);
210 this.mine_time = time + WEP_CVAR(WEP_MINE_LAYER, lifetime_countdown);
211 this.mine_explodeanyway = 1; // make the mine super aggressive -- Samual: Rather, make it not care if a teammate is near.
212 }
213
214 // a player's mines shall explode if they disconnect or die
215 if (!IS_PLAYER(this.realowner) || IS_DEAD(this.realowner) || STAT(FROZEN, this.realowner))
216 {
219 return;
220 }
221
222 // set the mine for detonation when a foe gets close enough
223 float time_core = WEP_CVAR(WEP_MINE_LAYER, proximity_time_core);
224 float time_edge = WEP_CVAR(WEP_MINE_LAYER, proximity_time_edge);
225 float proxrad = WEP_CVAR(WEP_MINE_LAYER, proximity_radius);
226 float new_mine_time;
229 for (; head; head = head.chain)
230 {
231 if (!this.mine_time) // don't repeat the sound
232 spamsound(this, CH_SHOTS, SND_MINE_TRIGGER, VOL_BASE, ATTN_NORM);
233 // scale from time_edge to time_core based on how close the player is to the mine
234 new_mine_time = time + time_core;
235 if (time_edge != time_core)
236 new_mine_time += (time_edge - time_core) * vlen(head.WarpZone_findradius_dist) / proxrad;
237 if (!this.mine_time || this.mine_time > new_mine_time) // choose the earliest explosion time
238 this.mine_time = new_mine_time;
239 }
240
241 // explode if it's time to
242 if (this.mine_time && time >= this.mine_time)
243 {
245 return;
246 }
247
248 // remote detonation
249 .entity weaponentity = this.weaponentity_fld;
250 if (this.realowner.(weaponentity).m_weapon == WEP_MINE_LAYER
251 && !IS_DEAD(this.realowner)
252 && this.minelayer_detonate)
253 {
255 return;
256 }
257
258 // if it was detached by damage but landed during the bounce time, reenable gravity so it will touch and reattach
259 if (this.move_movetype == MOVETYPE_BOUNCE && IS_ONGROUND(this))
260 UNSET_ONGROUND(this);
261}
262
264{
265 if (this.move_movetype == MOVETYPE_NONE
267 return; // we're already a stuck mine, why do we get called? TODO does this even happen?
268 if (time <= this.wait)
269 return; // don't reattach yet
270
272
273 if (toucher.solid == SOLID_BSP)
275}
276
277void W_MineLayer_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
278{
279 if (GetResource(this, RES_HEALTH) <= 0)
280 return;
281
282 // Reading the cvar here because this.damageforcescale is overridden in blaster.qc
283 // this way the blaster can hit mines midair but can only detach them when enabled by this cvar.
284 if (WEP_CVAR(WEP_MINE_LAYER, damageforcescale) && inflictor.classname != "mine")
285 {
286 set_movetype(this, MOVETYPE_BOUNCE); // not TOSS: so a direct perpendicular hit can move the mine
287 this.wait = time + 0.0625; // after this time it will reattach instead of bouncing
289 this.avelocity += force * -WEP_CVAR(WEP_MINE_LAYER, damageforcescale);
290 }
291
292 float is_from_enemy = (inflictor.realowner != this.realowner);
293
294 if (!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, (is_from_enemy ? 1 : -1)))
295 return; // g_projectiles_damage says to halt
296
297 TakeResource(this, RES_HEALTH, damage);
298 this.angles = vectoangles(this.velocity);
299
300 if (GetResource(this, RES_HEALTH) <= 0)
302}
303
304void W_MineLayer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
305{
306 // scan how many mines we placed, and return if we reached our limit
307 if (WEP_CVAR(WEP_MINE_LAYER, limit) && W_MineLayer_Count(actor, weaponentity) >= WEP_CVAR(WEP_MINE_LAYER, limit))
308 {
309 // the refire delay keeps this message from being spammed
310 Send_Notification(NOTIF_ONE, actor, MSG_MULTI, WEAPON_MINELAYER_LIMIT, WEP_CVAR(WEP_MINE_LAYER, limit));
311 play2(actor, SND(UNAVAILABLE));
312 return;
313 }
314
315 W_DecreaseAmmo(thiswep, actor, WEP_CVAR(WEP_MINE_LAYER, ammo), weaponentity);
316
317 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);
318 W_MuzzleFlash(thiswep, actor, weaponentity, w_shotorg, w_shotdir);
319
320 entity mine = new(mine);
321 WarpZone_RefSys_Copy(mine, actor);
322 mine.weaponentity_fld = weaponentity;
323 IL_PUSH(g_mines, mine);
324 mine.owner = mine.realowner = actor;
325 if (WEP_CVAR(WEP_MINE_LAYER, detonatedelay) >= 0)
326 mine.spawnshieldtime = time + WEP_CVAR(WEP_MINE_LAYER, detonatedelay);
327 else
328 mine.spawnshieldtime = -1;
329 mine.bot_dodge = true;
330 mine.bot_dodgerating = WEP_CVAR(WEP_MINE_LAYER, damage) * 2; // * 2 because it can detonate inflight which makes it even more dangerous
331
332 mine.takedamage = DAMAGE_YES;
333 mine.damageforcescale = WEP_CVAR(WEP_MINE_LAYER, damageforcescale);
334 SetResourceExplicit(mine, RES_HEALTH, WEP_CVAR(WEP_MINE_LAYER, health));
335 mine.event_damage = W_MineLayer_Damage;
336 mine.damagedbycontents = true;
338
341 mine.projectiledeathtype = thiswep.m_id;
342 mine.weaponentity_fld = weaponentity;
343 setsize(mine, '-4 -4 -4', '4 4 4'); // give it some size so it can be shot
344
345 setorigin(mine, w_shotorg - v_forward * 4); // move it back so it hits the wall at the right point
346 W_SetupProjVelocity_Basic(mine, WEP_CVAR(WEP_MINE_LAYER, speed), 0);
347 mine.angles = vectoangles(mine.velocity);
348
351 mine.nextthink = time;
352 mine.cnt = (WEP_CVAR(WEP_MINE_LAYER, lifetime) - WEP_CVAR(WEP_MINE_LAYER, lifetime_countdown));
353 mine.flags = FL_PROJECTILE;
354 IL_PUSH(g_projectiles, mine);
355 IL_PUSH(g_bot_dodge, mine);
356 mine.missile_flags = MIF_SPLASH | MIF_ARC | MIF_PROXY;
357
358 if (mine.cnt > 0)
359 mine.cnt += time;
360
361 CSQCProjectile(mine, true, PROJECTILE_MINE, true);
362
363 // common properties
364
365 MUTATOR_CALLHOOK(EditProjectile, actor, mine);
366}
367
368bool W_MineLayer_PlacedMines(entity this, .entity weaponentity, bool detonate)
369{
370 bool minfound = false;
371 IL_EACH(g_mines, it.realowner == this && it.weaponentity_fld == weaponentity,
372 {
373 if (detonate)
374 {
375 if (!it.minelayer_detonate)
376 {
377 it.minelayer_detonate = true;
378 minfound = true;
379 }
380 }
381 else
382 minfound = true;
383 });
384 return minfound;
385}
386
387METHOD(MineLayer, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
388{
389 // aim and decide to fire if appropriate
390 if (WEP_CVAR(WEP_MINE_LAYER, limit) && W_MineLayer_Count(actor, weaponentity) >= WEP_CVAR(WEP_MINE_LAYER, limit))
391 PHYS_INPUT_BUTTON_ATCK(actor) = false;
392 else
393 PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(WEP_MINE_LAYER, speed), 0, WEP_CVAR(WEP_MINE_LAYER, lifetime), false, false);
394
395 if (skill >= 2) // skill 0 and 1 bots won't detonate mines!
396 {
397 // decide whether to detonate mines
398 float edgedamage, coredamage, edgeradius, recipricoledgeradius;
399 float selfdamage, teamdamage, enemydamage;
400 edgedamage = WEP_CVAR(WEP_MINE_LAYER, edgedamage);
401 coredamage = WEP_CVAR(WEP_MINE_LAYER, damage);
402 edgeradius = WEP_CVAR(WEP_MINE_LAYER, radius);
403 recipricoledgeradius = 1 / edgeradius;
404 selfdamage = 0;
405 teamdamage = 0;
406 enemydamage = 0;
407
408 IL_EACH(g_mines, it.realowner == actor,
409 {
410 entity mine = it;
411 IL_EACH(g_bot_targets, it.bot_attack,
412 {
413 float d = vlen(it.origin + (it.mins + it.maxs) * 0.5 - mine.origin);
414 d = bound(0, edgedamage + (coredamage - edgedamage) * sqrt(1 - d * recipricoledgeradius), 10000);
415 // count potential damage according to type of target
416 if (it == actor)
417 selfdamage += d;
418 else if (SAME_TEAM(it, actor))
419 teamdamage += d;
420 else if (bot_shouldattack(actor, it))
421 enemydamage += d;
422 });
423 });
424
425 float desirabledamage = enemydamage;
426 if (StatusEffects_active(STATUSEFFECT_Shield, actor) && !StatusEffects_active(STATUSEFFECT_SpawnShield, actor))
427 desirabledamage -= selfdamage * autocvar_g_balance_selfdamagepercent;
428 if (teamplay && actor.team)
429 desirabledamage -= teamdamage;
430
431 makevectors(actor.v_angle);
432 IL_EACH(g_mines, it.realowner == actor,
433 {
434 if (skill > 9) // normal players only do this for the target they are tracking
435 {
436 entity mine = it;
437 IL_EACH(g_bot_targets, it.bot_attack,
438 {
439 if (v_forward * normalize(mine.origin - it.origin) < 0.1
440 && desirabledamage >= 0.1 * coredamage)
441 PHYS_INPUT_BUTTON_ATCK2(actor) = true;
442 });
443 }
444 else
445 {
446 // As the distance gets larger, a correct detonation gets near imposible
447 // Bots are assumed to use the mine spawnfunc_light to see if the mine gets near a player
448 if (v_forward * normalize(it.origin - actor.enemy.origin) < 0.1
449 && IS_PLAYER(actor.enemy)
450 && desirabledamage >= 0.1 * coredamage)
451 {
452 float distance = bound(300, vlen(actor.origin - actor.enemy.origin), 30000);
453 if (random() / distance * 300 > frametime * bound(0, (10 - skill) * 0.2, 1))
454 PHYS_INPUT_BUTTON_ATCK2(actor) = true;
455 }
456 }
457 });
458
459 // if we would be doing at X percent of the core damage, detonate it
460 // but don't fire a new shot at the same time!
461 if (desirabledamage >= 0.75 * coredamage) // this should do group damage in rare fortunate events
462 PHYS_INPUT_BUTTON_ATCK2(actor) = true;
463 if (skill > 6.5 && selfdamage > GetResource(actor, RES_HEALTH))
464 PHYS_INPUT_BUTTON_ATCK2(actor) = false;
465 //if (PHYS_INPUT_BUTTON_ATCK2(actor) == true)
466 // dprint(ftos(desirabledamage), "\n");
467 if (PHYS_INPUT_BUTTON_ATCK2(actor))
468 PHYS_INPUT_BUTTON_ATCK(actor) = false;
469 }
470}
471
472METHOD(MineLayer, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
473{
474 actor.(weaponentity).minelayer_mines = W_MineLayer_Count(actor, weaponentity);
475
476 if (autocvar_g_balance_minelayer_reload_ammo && actor.(weaponentity).clip_load < WEP_CVAR(WEP_MINE_LAYER, ammo)) // forced reload
477 {
478 // not if we're holding the minelayer without enough ammo, but can detonate existing mines
479 bool enough_ammo = (GetResource(actor, thiswep.ammo_type) >= WEP_CVAR(WEP_MINE_LAYER, ammo) || (actor.items & IT_UNLIMITED_AMMO));
480 if (!W_MineLayer_PlacedMines(actor, weaponentity, false) || enough_ammo)
481 thiswep.wr_reload(thiswep, actor, weaponentity);
482 }
483 else if (fire & 1)
484 {
485 if (weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(WEP_MINE_LAYER, refire)))
486 {
487 W_MineLayer_Attack(thiswep, actor, weaponentity);
488 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(WEP_MINE_LAYER, animtime), w_ready);
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 return W_MineLayer_PlacedMines(actor, weaponentity, false);
513}
514
515METHOD(MineLayer, wr_resetplayer, void(entity thiswep, entity actor))
516{
517 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
518 {
519 .entity weaponentity = weaponentities[slot];
520 actor.(weaponentity).minelayer_mines = 0;
521 }
522}
523
524METHOD(MineLayer, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
525{
526 W_Reload(actor, weaponentity, WEP_CVAR(WEP_MINE_LAYER, ammo), SND_RELOAD);
527}
528
529METHOD(MineLayer, wr_suicidemessage, Notification(entity thiswep))
530{
531 return WEAPON_MINELAYER_SUICIDE;
532}
533
534METHOD(MineLayer, wr_killmessage, Notification(entity thiswep))
535{
536 return WEAPON_MINELAYER_MURDER;
537}
538
539#endif // SVQC
540#ifdef CSQC
541
542METHOD(MineLayer, wr_impacteffect, void(entity thiswep, entity actor))
543{
544 vector org2 = w_org + w_backoff * 2;
545 pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
546 if (!w_issilent)
547 sound(actor, CH_SHOTS, SND_MINE_EXP, VOL_BASE, ATTN_NORM);
548}
549
550#endif // CSQC
551#ifdef MENUQC
556
557METHOD(MineLayer, describe, string(MineLayer this))
558{
559 TC(MineLayer, this);
561 PAR(_("The %s places mines on the ground when fired, which detonate and damage enemies if stepped on. "
562 "Only a couple mines can be placed at any time, and after some time they will self-detonate."), COLORED_NAME(this));
563 PAR(_("Uniquely, the mines explode sooner the closer an enemy comes to them. "
564 "The secondary fire can be used to detonate all mines placed by the primary fire."));
565 PAR(_("It consumes %s ammo for each mine laid."), COLORED_NAME(ITEM_Rockets));
566 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. "
567 "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));
568 PAR(W_Guide_Keybinds(this));
570 return PAGE_TEXT;
571}
572
573#endif // MENUQC
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.
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
Definition weapon.qh:42
int m_id
Definition weapon.qh:43
virtual void wr_checkammo1()
(SERVER) checks ammo for weapon primary
Definition weapon.qh:100
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:189
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:843
#define IS_DEAD(s)
Definition player.qh:244
#define IS_PLAYER(s)
Definition player.qh:242
#define PHYS_INPUT_BUTTON_ATCK(s)
Definition player.qh:152
#define PHYS_INPUT_BUTTON_ATCK2(s)
Definition player.qh:154
void SetMovetypeFollow(entity ent, entity e)
Definition util.qc:2141
void UnsetMovetypeFollow(entity ent)
Definition util.qc:2161
int LostMovetypeFollow(entity ent)
Definition util.qc:2171
const int FL_PROJECTILE
Definition constants.qh:77
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:937
IntrusiveList g_damagedbycontents
Definition damage.qh:143
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
set manually after projectile has bounced
Definition all.qh:33
float speed
Definition dynlight.qc:9
#define pointparticles(effect, org, vel, howmany)
Definition effect.qh:6
ent angles
Definition ent_cs.qc:146
SetResourceExplicit(ent, RES_ARMOR, ReadByte() *DEC_FACTOR)) ENTCS_PROP(NAME
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: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
void WarpZone_RefSys_Copy(entity me, entity from)
Copies the warpzone reference of from onto me.
Definition common.qc:824
noref entity WarpZone_SearchInRadius_otherent
Free to use in the callback.
Definition common.qh:71
#define MOVE_NOTHING
Definition common.qh:35
vector movedir
Definition viewloc.qh:18
float vlen(vector v)
vector vectoangles(vector v)
void W_MineLayer_ProximityExplode(entity this)
Definition minelayer.qc:167
void W_MineLayer_Explode_think(entity this)
Definition minelayer.qc:96
void W_MineLayer_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition minelayer.qc:277
int W_MineLayer_Count(entity e,.entity weaponentity)
Definition minelayer.qc:182
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:194
bool W_MineLayer_Think_cond(entity e)
Definition minelayer.qc:189
bool W_MineLayer_PlacedMines(entity this,.entity weaponentity, bool detonate)
Definition minelayer.qc:368
void W_MineLayer_Attack(Weapon thiswep, entity actor,.entity weaponentity)
Definition minelayer.qc:304
void W_MineLayer_Touch(entity this, entity toucher)
Definition minelayer.qc:263
bool W_MineLayer_CheckSameTeam_cond(entity e)
Definition minelayer.qc:138
void W_MineLayer_DoRemoteExplode(entity this)
Definition minelayer.qc:101
void W_MineLayer_RemoteExplode(entity this)
Definition minelayer.qc:142
IntrusiveList g_mines
Definition minelayer.qh:87
float minelayer_detonate
Definition minelayer.qh:84
float mine_explodeanyway
Definition minelayer.qh:84
float mine_time
Definition minelayer.qh:85
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
const int MOVETYPE_NONE
Definition movetypes.qh:133
const int MOVETYPE_FOLLOW
Definition movetypes.qh:145
float move_movetype
Definition movetypes.qh:80
#define UNSET_ONGROUND(s)
Definition movetypes.qh:18
const int MOVETYPE_TOSS
Definition movetypes.qh:139
const int MOVETYPE_BOUNCE
Definition movetypes.qh:143
#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:1500
entity Notification
always last
Definition all.qh:85
#define METHOD(cname, name, prototype)
Definition oo.qh:274
#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:96
entity entity toucher
Definition self.qh:76
#define settouch(e, f)
Definition self.qh:77
#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: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_PROXY
Definition common.qh:60
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 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: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_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:51
string W_Guide_Keybinds(Weapon wep)
Definition all.qc:824
void W_MuzzleFlash(Weapon thiswep, entity actor,.entity weaponentity, vector shotorg, vector shotdir)
Definition all.qc:715
string W_Guide_DPS_onlyOne_unnamed(string name)
Definition all.qc:901
#define WEP_CVAR(wep, name)
Definition all.qh:337
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