-#ifndef MUTATOR_NADES_H
-#define MUTATOR_NADES_H
+#include "nades.qh"
-#ifdef SVQC
-#include "../../../../server/mutators/mutator/gamemode_freezetag.qc"
-#endif
+#ifdef IMPLEMENTATION
-.entity nade;
-.entity fake_nade;
-.float nade_timer;
-.float nade_refire;
-.float bonus_nades;
-.float nade_special_time;
-.float bonus_nade_score;
-.float nade_type;
-.string pokenade_type;
-.entity nade_damage_target;
-.float cvar_cl_nade_type;
-.string cvar_cl_pokenade_type;
-.float toss_time;
-.float stat_healing_orb;
-.float stat_healing_orb_alpha;
-.float nade_show_particles;
-
-// Remove nades that are being thrown
-void nades_Clear(entity player);
-
-// Give a bonus grenade to a player
-void(entity player, float score) nades_GiveBonus;
-
-/**
- * called to adjust nade damage and force on hit
- */
-#define EV_Nade_Damage(i, o) \
- /** weapon */ i(entity, MUTATOR_ARGV_0_entity) \
- /** force */ i(vector, MUTATOR_ARGV_0_vector) \
- /**/ o(vector, MUTATOR_ARGV_0_vector) \
- /** damage */ i(float, MUTATOR_ARGV_0_float) \
- /**/ o(float, MUTATOR_ARGV_0_float) \
- /**/
-MUTATOR_HOOKABLE(Nade_Damage, EV_Nade_Damage);
+#ifndef MENUQC
+entity Nade_TrailEffect(int proj, int nade_team)
+{
+ switch (proj)
+ {
+ case PROJECTILE_NADE: return EFFECT_NADE_TRAIL(nade_team);
+ case PROJECTILE_NADE_BURN: return EFFECT_NADE_TRAIL_BURN(nade_team);
+ }
+ FOREACH(Nades, true, LAMBDA(
+ for (int j = 0; j < 2; j++)
+ {
+ if (it.m_projectile[j] == proj)
+ {
+ string trail = it.m_trail[j].eent_eff_name;
+ if (trail) return it.m_trail[j];
+ break;
+ }
+ }
+ ));
+
+ return EFFECT_Null;
+}
#endif
-#ifdef IMPLEMENTATION
-
-#include "../../../nades/all.qh"
-#include "../../../gamemodes/all.qh"
-#include "../../../monsters/spawn.qh"
-#include "../../../monsters/sv_monsters.qh"
-#include "../../../../server/g_subs.qh"
+#ifdef CSQC
+REGISTER_MUTATOR(cl_nades, true);
+MUTATOR_HOOKFUNCTION(cl_nades, HUD_Draw_overlay)
+{
+ if (STAT(HEALING_ORB) <= time) return false;
+ MUTATOR_ARGV(0, vector) = NADE_TYPE_HEAL.m_color;
+ MUTATOR_ARGV(0, float) = STAT(HEALING_ORB_ALPHA);
+ return true;
+}
+MUTATOR_HOOKFUNCTION(cl_nades, Ent_Projectile)
+{
+ if (self.cnt == PROJECTILE_NAPALM_FOUNTAIN)
+ {
+ self.modelindex = 0;
+ self.traileffect = EFFECT_FIREBALL.m_id;
+ return true;
+ }
+ if (Nade_FromProjectile(self.cnt) != NADE_TYPE_Null)
+ {
+ setmodel(self, MDL_PROJECTILE_NADE);
+ entity trail = Nade_TrailEffect(self.cnt, self.team);
+ if (trail.eent_eff_name) self.traileffect = trail.m_id;
+ return true;
+ }
+}
+MUTATOR_HOOKFUNCTION(cl_nades, EditProjectile)
+{
+ if (self.cnt == PROJECTILE_NAPALM_FOUNTAIN)
+ {
+ loopsound(self, CH_SHOTS_SINGLE, SND(FIREBALL_FLY2), VOL_BASE, ATTEN_NORM);
+ self.mins = '-16 -16 -16';
+ self.maxs = '16 16 16';
+ }
-REGISTER_MUTATOR(nades, cvar("g_nades"))
+ entity nade_type = Nade_FromProjectile(self.cnt);
+ if (nade_type == NADE_TYPE_Null) return;
+ self.mins = '-16 -16 -16';
+ self.maxs = '16 16 16';
+ self.colormod = nade_type.m_color;
+ self.move_movetype = MOVETYPE_BOUNCE;
+ self.move_touch = func_null;
+ self.scale = 1.5;
+ self.avelocity = randomvec() * 720;
+
+ if (nade_type == NADE_TYPE_TRANSLOCATE || nade_type == NADE_TYPE_SPAWN)
+ self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+ else
+ self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
+}
+bool Projectile_isnade(int p)
{
- MUTATOR_ONADD
+ return Nade_FromProjectile(p) != NADE_TYPE_Null;
+}
+void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time)
+{
+ float bonusNades = STAT(NADE_BONUS);
+ float bonusProgress = STAT(NADE_BONUS_SCORE);
+ float bonusType = STAT(NADE_BONUS_TYPE);
+ Nade def = Nades_from(bonusType);
+ vector nadeColor = def.m_color;
+ string nadeIcon = def.m_icon;
+
+ vector iconPos, textPos;
+
+ if(autocvar_hud_panel_ammo_iconalign)
+ {
+ iconPos = myPos + eX * 2 * mySize.y;
+ textPos = myPos;
+ }
+ else
{
- addstat(STAT_NADE_TIMER, AS_FLOAT, nade_timer);
- addstat(STAT_NADE_BONUS, AS_FLOAT, bonus_nades);
- addstat(STAT_NADE_BONUS_TYPE, AS_INT, nade_type);
- addstat(STAT_NADE_BONUS_SCORE, AS_FLOAT, bonus_nade_score);
- addstat(STAT_HEALING_ORB, AS_FLOAT, stat_healing_orb);
- addstat(STAT_HEALING_ORB_ALPHA, AS_FLOAT, stat_healing_orb_alpha);
+ iconPos = myPos;
+ textPos = myPos + eX * mySize.y;
}
- return false;
+ if(bonusNades > 0 || bonusProgress > 0)
+ {
+ DrawNadeProgressBar(myPos, mySize, bonusProgress, nadeColor);
+
+ if(autocvar_hud_panel_ammo_text)
+ drawstring_aspect(textPos, ftos(bonusNades), eX * (2/3) * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ if(draw_expanding)
+ drawpic_aspect_skin_expanding(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, expand_time);
+
+ drawpic_aspect_skin(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
}
+#endif
+
+#ifdef SVQC
+
+#include <common/gamemodes/all.qh>
+#include <common/monsters/spawn.qh>
+#include <common/monsters/sv_monsters.qh>
+#include <server/g_subs.qh>
+
+REGISTER_MUTATOR(nades, cvar("g_nades"));
.float nade_time_primed;
for(e = findradius(self.origin, autocvar_g_nades_nade_radius); e; e = e.chain)
if(e != self)
if(!autocvar_g_nades_ice_teamcheck || (DIFF_TEAM(e, self.realowner) || e == self.realowner))
- if(e.takedamage && e.deadflag == DEAD_NO)
+ if(e.takedamage && !IS_DEAD(e))
if(e.health > 0)
if(!e.revival_time || ((time - e.revival_time) >= 1.5))
if(!e.frozen)
float maxhealth;
float health_factor;
if(IS_PLAYER(other) || IS_MONSTER(other))
- if(other.deadflag == DEAD_NO)
+ if(!IS_DEAD(other))
if(!other.frozen)
{
health_factor = autocvar_g_nades_heal_rate*frametime/2;
void nade_touch()
{SELFPARAM();
+ if(other)
+ UpdateCSQCProjectile(self);
+
+ if(other == self.realowner)
+ return; // no self impacts
/*float is_weapclip = 0;
if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NODRAW)
if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NONSOLID))
self.velocity += force;
UpdateCSQCProjectile(self);
- if(damage <= 0 || ((self.flags & FL_ONGROUND) && IS_PLAYER(attacker)))
+ if(damage <= 0 || ((IS_ONGROUND(self)) && IS_PLAYER(attacker)))
return;
if(self.health == self.max_health)
if (IS_REAL_CLIENT(player))
if (IS_PLAYER(player) && player.bonus_nades < autocvar_g_nades_bonus_max)
if (player.frozen == 0)
- if (player.deadflag == DEAD_NO)
+ if (!IS_DEAD(player))
{
if ( player.bonus_nade_score < 1 )
player.bonus_nade_score += score/autocvar_g_nades_bonus_score_max;
fn.colormod = Nades_from(n.nade_type).m_color;
fn.colormap = self.colormap;
fn.glowmod = self.glowmod;
- fn.think = SUB_Remove;
+ fn.think = SUB_Remove_self;
fn.nextthink = n.wait;
self.nade = n;
if(gameover)
return false;
- if(self.deadflag != DEAD_NO)
+ if(IS_DEAD(self))
return false;
if (!autocvar_g_nades)
{
vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
n = 0;
- FOR_EACH_PLAYER(other) if(self != other)
- {
- if(other.deadflag == DEAD_NO)
- if(other.frozen == 0)
- if(SAME_TEAM(other, self))
- if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
+ FOREACH_CLIENT(IS_PLAYER(it) && it != self, LAMBDA(
+ if(!IS_DEAD(it))
+ if(it.frozen == 0)
+ if(SAME_TEAM(it, self))
+ if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, it.absmin, it.absmax))
{
if(!o)
- o = other;
+ o = it;
if(self.frozen == 1)
- other.reviving = true;
+ it.reviving = true;
++n;
}
- }
+ ));
}
if(n && self.frozen == 3) // OK, there is at least one teammate reviving us
Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, self.netname);
}
- FOR_EACH_PLAYER(other) if(other.reviving)
- {
+ FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, LAMBDA(
other.revive_progress = self.revive_progress;
other.reviving = false;
- }
+ ));
}
return false;
ret_string = strcat(ret_string, ", Nades");
return false;
}
+
+MUTATOR_HOOKFUNCTION(nades, BuildGameplayTipsString)
+{
+ ret_string = strcat(ret_string, "\n\n^3nades^8 are enabled, press 'g' to use them\n");
+ return false;
+}
+
+#endif
#endif