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
139{
140 if (IS_DEAD(this.realowner))
141 return;
142 if (this.spawnshieldtime >= 0)
143 {
144 if (time < this.spawnshieldtime) // timer
145 return;
146 }
147 else
148 {
149 /* make sure no friend is in the mine's radius.
150 * WEAPONTODO: modify protection cvar to allow disabling remote detonation protection.
151 * disabling it currently allows Mine Layer-flying, even more powerful than rocket-flying
152 * ... even without Rocket Flying mutator enabled
153 */
154 entity head = WarpZone_FindRadius(this.origin, WEP_CVAR(WEP_MINE_LAYER, remote_radius), false);
155 for (; head; head = head.chain)
156 if (SAME_TEAM(head, this.realowner))
157 return;
158 }
159
161}
162
164{
165 // make sure no friend is in the mine's radius. If there is any, explosion is delayed until they're at a safe distance
166 if (WEP_CVAR(WEP_MINE_LAYER, protection) && this.mine_explodeanyway == 0)
167 {
168 entity head = WarpZone_FindRadius(this.origin, WEP_CVAR(WEP_MINE_LAYER, radius), false);
169 for (; head; head = head.chain)
170 if (SAME_TEAM(head, this.realowner))
171 return;
172 }
173
174 this.mine_time = 0;
176}
177
178int W_MineLayer_Count(entity e, .entity weaponentity)
179{
180 int minecount = 0;
181 IL_EACH(g_mines, it.realowner == e && it.weaponentity_fld == weaponentity, ++minecount);
182 return minecount;
183}
184
186{
187 this.nextthink = time;
188
190 {
193 }
194
195 // our lifetime has expired, it's time to die - mine_time just allows us to play a sound for this
196 // WEAPONTODO: replace this mine_trigger.wav sound with a real countdown
197 if (time > this.cnt && !this.mine_time && this.cnt > 0)
198 {
199 if (WEP_CVAR(WEP_MINE_LAYER, lifetime_countdown) > 0)
200 spamsound(this, CH_SHOTS, SND_MINE_TRIGGER, VOL_BASE, ATTN_NORM);
201 this.mine_time = time + WEP_CVAR(WEP_MINE_LAYER, lifetime_countdown);
202 this.mine_explodeanyway = 1; // make the mine super aggressive -- Samual: Rather, make it not care if a teammate is near.
203 }
204
205 // a player's mines shall explode if they disconnect or die
206 if (!IS_PLAYER(this.realowner) || IS_DEAD(this.realowner) || STAT(FROZEN, this.realowner))
207 {
210 return;
211 }
212
213 // set the mine for detonation when a foe gets close enough
214 float time_core = WEP_CVAR(WEP_MINE_LAYER, proximity_time_core);
215 float time_edge = WEP_CVAR(WEP_MINE_LAYER, proximity_time_edge);
216 float proxrad = WEP_CVAR(WEP_MINE_LAYER, proximity_radius);
217 float new_mine_time;
218 entity head = WarpZone_FindRadius(this.origin, proxrad, false);
219 for (; head; head = head.chain)
220 if (IS_PLAYER(head) && !IS_DEAD(head) && !STAT(FROZEN, head) && !IS_INDEPENDENT_PLAYER(head)
221 && DIFF_TEAM(head, this.realowner)) // don't trigger for team mates
222 {
223 if (!this.mine_time) // don't repeat the sound
224 spamsound(this, CH_SHOTS, SND_MINE_TRIGGER, VOL_BASE, ATTN_NORM);
225 // scale from time_edge to time_core based on how close the player is to the mine
226 new_mine_time = time + time_core;
227 if (time_edge != time_core)
228 new_mine_time += (time_edge - time_core) * vlen(head.WarpZone_findradius_dist) / proxrad;
229 if (!this.mine_time || this.mine_time > new_mine_time) // choose the earliest explosion time
230 this.mine_time = new_mine_time;
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 && !IS_DEAD(this.realowner)
244 && 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{
257 if (this.move_movetype == MOVETYPE_NONE
259 return; // we're already a stuck mine, why do we get called? TODO does this even happen?
260 if (time <= this.wait)
261 return; // don't reattach yet
262
264
265 if (toucher.solid == SOLID_BSP)
267}
268
269void W_MineLayer_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
270{
271 if (GetResource(this, RES_HEALTH) <= 0)
272 return;
273
274 // Reading the cvar here because this.damageforcescale is overridden in blaster.qc
275 // this way the blaster can hit mines midair but can only detach them when enabled by this cvar.
276 if (WEP_CVAR(WEP_MINE_LAYER, damageforcescale) && inflictor.classname != "mine")
277 {
278 set_movetype(this, MOVETYPE_BOUNCE); // not TOSS: so a direct perpendicular hit can move the mine
279 this.wait = time + 0.0625; // after this time it will reattach instead of bouncing
281 this.avelocity += force * -WEP_CVAR(WEP_MINE_LAYER, damageforcescale);
282 }
283
284 float is_from_enemy = (inflictor.realowner != this.realowner);
285
286 if (!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, (is_from_enemy ? 1 : -1)))
287 return; // g_projectiles_damage says to halt
288
289 TakeResource(this, RES_HEALTH, damage);
290 this.angles = vectoangles(this.velocity);
291
292 if (GetResource(this, RES_HEALTH) <= 0)
294}
295
296void W_MineLayer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
297{
298 // scan how many mines we placed, and return if we reached our limit
299 if (WEP_CVAR(WEP_MINE_LAYER, limit) && W_MineLayer_Count(actor, weaponentity) >= WEP_CVAR(WEP_MINE_LAYER, limit))
300 {
301 // the refire delay keeps this message from being spammed
302 Send_Notification(NOTIF_ONE, actor, MSG_MULTI, WEAPON_MINELAYER_LIMIT, WEP_CVAR(WEP_MINE_LAYER, limit));
303 play2(actor, SND(UNAVAILABLE));
304 return;
305 }
306
307 W_DecreaseAmmo(thiswep, actor, WEP_CVAR(WEP_MINE_LAYER, ammo), weaponentity);
308
309 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);
310 W_MuzzleFlash(thiswep, actor, weaponentity, w_shotorg, w_shotdir);
311
313 mine.weaponentity_fld = weaponentity;
314 IL_PUSH(g_mines, mine);
315 mine.owner = mine.realowner = actor;
316 if (WEP_CVAR(WEP_MINE_LAYER, detonatedelay) >= 0)
317 mine.spawnshieldtime = time + WEP_CVAR(WEP_MINE_LAYER, detonatedelay);
318 else
319 mine.spawnshieldtime = -1;
320 mine.classname = "mine";
321 mine.bot_dodge = true;
322 mine.bot_dodgerating = WEP_CVAR(WEP_MINE_LAYER, damage) * 2; // * 2 because it can detonate inflight which makes it even more dangerous
323
324 mine.takedamage = DAMAGE_YES;
325 mine.damageforcescale = WEP_CVAR(WEP_MINE_LAYER, damageforcescale);
326 SetResourceExplicit(mine, RES_HEALTH, WEP_CVAR(WEP_MINE_LAYER, health));
327 mine.event_damage = W_MineLayer_Damage;
328 mine.damagedbycontents = true;
330
333 mine.projectiledeathtype = thiswep.m_id;
334 mine.weaponentity_fld = weaponentity;
335 setsize(mine, '-4 -4 -4', '4 4 4'); // give it some size so it can be shot
336
337 setorigin(mine, w_shotorg - v_forward * 4); // move it back so it hits the wall at the right point
338 W_SetupProjVelocity_Basic(mine, WEP_CVAR(WEP_MINE_LAYER, speed), 0);
339 mine.angles = vectoangles(mine.velocity);
340
343 mine.nextthink = time;
344 mine.cnt = (WEP_CVAR(WEP_MINE_LAYER, lifetime) - WEP_CVAR(WEP_MINE_LAYER, lifetime_countdown));
345 mine.flags = FL_PROJECTILE;
346 IL_PUSH(g_projectiles, mine);
347 IL_PUSH(g_bot_dodge, mine);
348 mine.missile_flags = MIF_SPLASH | MIF_ARC | MIF_PROXY;
349
350 if (mine.cnt > 0)
351 mine.cnt += time;
352
353 CSQCProjectile(mine, true, PROJECTILE_MINE, true);
354
355 // common properties
356
357 MUTATOR_CALLHOOK(EditProjectile, actor, mine);
358}
359
360bool W_MineLayer_PlacedMines(entity this, .entity weaponentity, bool detonate)
361{
362 bool minfound = false;
363 IL_EACH(g_mines, it.realowner == this && it.weaponentity_fld == weaponentity,
364 {
365 if (detonate)
366 {
367 if (!it.minelayer_detonate)
368 {
369 it.minelayer_detonate = true;
370 minfound = true;
371 }
372 }
373 else
374 minfound = true;
375 });
376 return minfound;
377}
378
379METHOD(MineLayer, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
380{
381 // aim and decide to fire if appropriate
382 if (WEP_CVAR(WEP_MINE_LAYER, limit) && W_MineLayer_Count(actor, weaponentity) >= WEP_CVAR(WEP_MINE_LAYER, limit))
383 PHYS_INPUT_BUTTON_ATCK(actor) = false;
384 else
385 PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(WEP_MINE_LAYER, speed), 0, WEP_CVAR(WEP_MINE_LAYER, lifetime), false, false);
386
387 if (skill >= 2) // skill 0 and 1 bots won't detonate mines!
388 {
389 // decide whether to detonate mines
390 float edgedamage, coredamage, edgeradius, recipricoledgeradius;
391 float selfdamage, teamdamage, enemydamage;
392 edgedamage = WEP_CVAR(WEP_MINE_LAYER, edgedamage);
393 coredamage = WEP_CVAR(WEP_MINE_LAYER, damage);
394 edgeradius = WEP_CVAR(WEP_MINE_LAYER, radius);
395 recipricoledgeradius = 1 / edgeradius;
396 selfdamage = 0;
397 teamdamage = 0;
398 enemydamage = 0;
399
400 IL_EACH(g_mines, it.realowner == actor,
401 {
402 entity mine = it;
403 IL_EACH(g_bot_targets, it.bot_attack,
404 {
405 float d = vlen(it.origin + (it.mins + it.maxs) * 0.5 - mine.origin);
406 d = bound(0, edgedamage + (coredamage - edgedamage) * sqrt(1 - d * recipricoledgeradius), 10000);
407 // count potential damage according to type of target
408 if (it == actor)
409 selfdamage += d;
410 else if (SAME_TEAM(it, actor))
411 teamdamage += d;
412 else if (bot_shouldattack(actor, it))
413 enemydamage += d;
414 });
415 });
416
417 float desirabledamage = enemydamage;
418 if (StatusEffects_active(STATUSEFFECT_Shield, actor) && !StatusEffects_active(STATUSEFFECT_SpawnShield, actor))
419 desirabledamage -= selfdamage * autocvar_g_balance_selfdamagepercent;
420 if (teamplay && actor.team)
421 desirabledamage -= teamdamage;
422
423 makevectors(actor.v_angle);
424 IL_EACH(g_mines, it.realowner == actor,
425 {
426 if (skill > 9) // normal players only do this for the target they are tracking
427 {
428 entity mine = it;
429 IL_EACH(g_bot_targets, it.bot_attack,
430 {
431 if (v_forward * normalize(mine.origin - it.origin) < 0.1
432 && desirabledamage >= 0.1 * coredamage)
433 PHYS_INPUT_BUTTON_ATCK2(actor) = true;
434 });
435 }
436 else
437 {
438 // As the distance gets larger, a correct detonation gets near imposible
439 // Bots are assumed to use the mine spawnfunc_light to see if the mine gets near a player
440 if (v_forward * normalize(it.origin - actor.enemy.origin) < 0.1
441 && IS_PLAYER(actor.enemy)
442 && desirabledamage >= 0.1 * coredamage)
443 {
444 float distance = bound(300, vlen(actor.origin - actor.enemy.origin), 30000);
445 if (random() / distance * 300 > frametime * bound(0, (10 - skill) * 0.2, 1))
446 PHYS_INPUT_BUTTON_ATCK2(actor) = true;
447 }
448 }
449 });
450
451 // if we would be doing at X percent of the core damage, detonate it
452 // but don't fire a new shot at the same time!
453 if (desirabledamage >= 0.75 * coredamage) // this should do group damage in rare fortunate events
454 PHYS_INPUT_BUTTON_ATCK2(actor) = true;
455 if (skill > 6.5 && selfdamage > GetResource(actor, RES_HEALTH))
456 PHYS_INPUT_BUTTON_ATCK2(actor) = false;
457 //if (PHYS_INPUT_BUTTON_ATCK2(actor) == true)
458 // dprint(ftos(desirabledamage), "\n");
459 if (PHYS_INPUT_BUTTON_ATCK2(actor))
460 PHYS_INPUT_BUTTON_ATCK(actor) = false;
461 }
462}
463
464METHOD(MineLayer, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
465{
466 actor.(weaponentity).minelayer_mines = W_MineLayer_Count(actor, weaponentity);
467
468 if (autocvar_g_balance_minelayer_reload_ammo && actor.(weaponentity).clip_load < WEP_CVAR(WEP_MINE_LAYER, ammo)) // forced reload
469 {
470 // not if we're holding the minelayer without enough ammo, but can detonate existing mines
471 bool enough_ammo = (GetResource(actor, thiswep.ammo_type) >= WEP_CVAR(WEP_MINE_LAYER, ammo) || (actor.items & IT_UNLIMITED_AMMO));
472 if (!W_MineLayer_PlacedMines(actor, weaponentity, false) || enough_ammo)
473 thiswep.wr_reload(thiswep, actor, weaponentity);
474 }
475 else if (fire & 1)
476 {
477 if (weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(WEP_MINE_LAYER, refire)))
478 {
479 W_MineLayer_Attack(thiswep, actor, weaponentity);
480 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(WEP_MINE_LAYER, animtime), w_ready);
481 }
482 }
483 if (fire & 2)
484 {
485 if (W_MineLayer_PlacedMines(actor, weaponentity, true))
486 sound(actor, CH_WEAPON_B, SND_MINE_DET, VOL_BASE, ATTN_NORM);
487 }
488}
489
490METHOD(MineLayer, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
491{
492 // actually do // don't switch while placing a mine
493 //if (ATTACK_FINISHED(actor, weaponentity) <= time || PS(actor).m_weapon != WEP_MINE_LAYER)
494 //{
495 float ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR(WEP_MINE_LAYER, ammo);
496 ammo_amount += actor.(weaponentity).(weapon_load[thiswep.m_id]) >= WEP_CVAR(WEP_MINE_LAYER, ammo);
497 return ammo_amount;
498 //}
499 //return true;
500}
501
502METHOD(MineLayer, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
503{
504 return W_MineLayer_PlacedMines(actor, weaponentity, false);
505}
506
507METHOD(MineLayer, wr_resetplayer, void(entity thiswep, entity actor))
508{
509 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
510 {
511 .entity weaponentity = weaponentities[slot];
512 actor.(weaponentity).minelayer_mines = 0;
513 }
514}
515
516METHOD(MineLayer, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
517{
518 W_Reload(actor, weaponentity, WEP_CVAR(WEP_MINE_LAYER, ammo), SND_RELOAD);
519}
520
521METHOD(MineLayer, wr_suicidemessage, Notification(entity thiswep))
522{
523 return WEAPON_MINELAYER_SUICIDE;
524}
525
526METHOD(MineLayer, wr_killmessage, Notification(entity thiswep))
527{
528 return WEAPON_MINELAYER_MURDER;
529}
530
531#endif // SVQC
532#ifdef CSQC
533
534METHOD(MineLayer, wr_impacteffect, void(entity thiswep, entity actor))
535{
536 vector org2 = w_org + w_backoff * 2;
537 pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
538 if (!w_issilent)
539 sound(actor, CH_SHOTS, SND_MINE_EXP, VOL_BASE, ATTN_NORM);
540}
541
542#endif // CSQC
543#ifdef MENUQC
548#include "devastator.qh"
549
550METHOD(MineLayer, describe, string(MineLayer this))
551{
552 TC(MineLayer, this);
554 PAR(_("The %s places mines on the ground when fired, which detonate and damage enemies if stepped on. "
555 "Only a couple mines can be placed at any time, and after several seconds they will self-detonate."), COLORED_NAME(this));
556 PAR(_("The secondary fire instantaneously detonates any mines placed by the primary fire, similar to the %s."), COLORED_NAME(WEP_DEVASTATOR));
557 PAR(_("It consumes %s ammo for each mine laid."), COLORED_NAME(ITEM_Rockets));
558 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. "
559 "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));
560 PAR(W_Guide_Keybinds(this));
562 return PAGE_TEXT;
563}
564
565#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.
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
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: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: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:2129
void UnsetMovetypeFollow(entity ent)
Definition util.qc:2149
int LostMovetypeFollow(entity ent)
Definition util.qc:2159
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:943
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
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:684
entity WarpZone_RefSys_SpawnSameRefSys(entity me)
Definition common.qc:806
vector movedir
Definition viewloc.qh:18
float vlen(vector v)
vector vectoangles(vector v)
void W_MineLayer_ProximityExplode(entity this)
Definition minelayer.qc:163
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:269
int W_MineLayer_Count(entity e,.entity weaponentity)
Definition minelayer.qc:178
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:185
bool W_MineLayer_PlacedMines(entity this,.entity weaponentity, bool detonate)
Definition minelayer.qc:360
void W_MineLayer_Attack(Weapon thiswep, entity actor,.entity weaponentity)
Definition minelayer.qc:296
void W_MineLayer_Touch(entity this, entity toucher)
Definition minelayer.qc:255
void W_MineLayer_DoRemoteExplode(entity this)
Definition minelayer.qc:101
void W_MineLayer_RemoteExplode(entity this)
Definition minelayer.qc:138
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: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: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_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: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