REGISTER_MUTATOR(cl_nades, true);
MUTATOR_HOOKFUNCTION(cl_nades, HUD_Draw_overlay)
{
- if (STAT(HEALING_ORB) <= time) return false;
- M_ARGV(0, vector) = NADE_TYPE_HEAL.m_color;
- M_ARGV(1, float) = STAT(HEALING_ORB_ALPHA);
- return true;
+ if (STAT(HEALING_ORB) > time)
+ {
- MUTATOR_ARGV(0, vector) = NADE_TYPE_HEAL.m_color;
- MUTATOR_ARGV(0, float) = STAT(HEALING_ORB_ALPHA);
++ M_ARGV(0, vector) = NADE_TYPE_HEAL.m_color;
++ M_ARGV(1, float) = STAT(HEALING_ORB_ALPHA);
+ return true;
+ }
+ if (STAT(ENTRAP_ORB) > time)
+ {
- MUTATOR_ARGV(0, vector) = NADE_TYPE_ENTRAP.m_color;
- MUTATOR_ARGV(0, float) = STAT(ENTRAP_ORB_ALPHA);
++ M_ARGV(0, vector) = NADE_TYPE_ENTRAP.m_color;
++ M_ARGV(1, float) = STAT(ENTRAP_ORB_ALPHA);
+ return true;
+ }
+ return false;
}
MUTATOR_HOOKFUNCTION(cl_nades, Ent_Projectile)
{
spawnloc.effects = EF_STARDUST;
spawnloc.cnt = autocvar_g_nades_spawn_count;
- if(self.realowner.nade_spawnloc)
+ if(this.realowner.nade_spawnloc)
{
- remove(self.realowner.nade_spawnloc);
- self.realowner.nade_spawnloc = world;
+ remove(this.realowner.nade_spawnloc);
+ this.realowner.nade_spawnloc = world;
}
- self.realowner.nade_spawnloc = spawnloc;
+ this.realowner.nade_spawnloc = spawnloc;
}
- void nades_orb_think()
- {SELFPARAM();
-void nade_heal_think(entity this)
++void nades_orb_think(entity this)
+ {
if(time >= this.ltime)
{
remove(this);
this.nade_show_particles = 0;
}
- orb.think = nades_orb_think;
+entity nades_spawn_orb(entity own, entity realown, vector org, float orb_ltime, float orb_rad)
+{
+ // NOTE: this function merely places an orb
+ // you must add a custom touch function to the returned entity if desired
+ // also set .colormod if you wish to have it colorized
+ entity orb = spawn(); // Net_LinkEntity sets the classname (TODO)
+ orb.owner = own;
+ orb.realowner = realown;
+ setorigin(orb, org);
+
+ orb.orb_lifetime = orb_ltime; // required for timers
+ orb.ltime = time + orb.orb_lifetime;
+ orb.bot_dodge = false;
+ orb.team = realown.team;
+ orb.solid = SOLID_TRIGGER;
+
+ setmodel(orb, MDL_NADE_ORB);
+ orb.orb_radius = orb_rad; // required for fading
+ vector size = '1 1 1' * orb.orb_radius / 2;
+ setsize(orb, -size, size);
+
+ Net_LinkEntity(orb, true, 0, orb_send);
+ orb.SendFlags |= 1;
+
- void nade_entrap_touch()
- {SELFPARAM();
- if(DIFF_TEAM(other, self.realowner)) // TODO: what if realowner changes team or disconnects?
++ setthink(orb, nades_orb_think);
+ orb.nextthink = time;
+
+ return orb;
+}
+
- STAT(ENTRAP_ORB_ALPHA, show_tint) = 0.75 * (self.ltime - time) / self.orb_lifetime;
++void nade_entrap_touch(entity this)
++{
++ if(DIFF_TEAM(other, this.realowner)) // TODO: what if realowner changes team or disconnects?
+ {
+ if (!isPushable(other))
+ return;
+
+ float pushdeltatime = time - other.lastpushtime;
+ if (pushdeltatime > 0.15) pushdeltatime = 0;
+ other.lastpushtime = time;
+ if(!pushdeltatime) return;
+
+ // div0: ticrate independent, 1 = identity (not 20)
+#ifdef SVQC
+ other.velocity = other.velocity * pow(autocvar_g_nades_entrap_strength, pushdeltatime);
+
+ UpdateCSQCProjectile(other);
+#elif defined(CSQC)
+ other.move_velocity = other.move_velocity * pow(autocvar_g_nades_entrap_strength, pushdeltatime);
+#endif
+
+ if ( IS_REAL_CLIENT(other) || IS_VEHICLE(other) )
+ {
+ entity show_tint = (IS_VEHICLE(other)) ? other.owner : other;
+ STAT(ENTRAP_ORB, show_tint) = time + 0.1;
- entity healer = nades_spawn_orb(this.owner, this.realowner, this.origin, autocvar_g_nades_entrap_time, autocvar_g_nades_entrap_radius);
++ STAT(ENTRAP_ORB_ALPHA, show_tint) = 0.75 * (this.ltime - time) / this.orb_lifetime;
+ }
+ }
+}
+
+void nade_entrap_boom(entity this)
+{
- healer.touch = nade_entrap_touch;
- healer.colormod = NADE_TYPE_ENTRAP.m_color;
++ entity orb = nades_spawn_orb(this.owner, this.realowner, this.origin, autocvar_g_nades_entrap_time, autocvar_g_nades_entrap_radius);
+
- void nade_heal_touch()
- {SELFPARAM();
++ settouch(orb, nade_entrap_touch);
++ orb.colormod = NADE_TYPE_ENTRAP.m_color;
+}
+
+ void nade_heal_touch(entity this)
+ {
float maxhealth;
float health_factor;
if(IS_PLAYER(other) || IS_MONSTER(other))
{
entity show_red = (IS_VEHICLE(other)) ? other.owner : other;
show_red.stat_healing_orb = time+0.1;
- show_red.stat_healing_orb_alpha = 0.75 * (self.ltime - time) / self.orb_lifetime;
- show_red.stat_healing_orb_alpha = 0.75 * (this.ltime - time) / this.healer_lifetime;
++ show_red.stat_healing_orb_alpha = 0.75 * (this.ltime - time) / this.orb_lifetime;
}
}
void nade_heal_boom(entity this)
{
- entity healer = nades_spawn_orb(this.owner, this.realowner, this.origin, autocvar_g_nades_heal_time, autocvar_g_nades_nade_radius);
- entity healer;
- healer = spawn();
- healer.owner = this.owner;
- healer.realowner = this.realowner;
- setorigin(healer, this.origin);
- healer.healer_lifetime = autocvar_g_nades_heal_time; // save the cvar
- healer.ltime = time + healer.healer_lifetime;
- healer.team = this.realowner.team;
- healer.bot_dodge = false;
- healer.solid = SOLID_TRIGGER;
- settouch(healer, nade_heal_touch);
-
- setmodel(healer, MDL_NADE_HEAL);
- healer.healer_radius = autocvar_g_nades_nade_radius;
- vector size = '1 1 1' * healer.healer_radius / 2;
- setsize(healer,-size,size);
-
- Net_LinkEntity(healer, true, 0, healer_send);
-
- setthink(healer, nade_heal_think);
- healer.nextthink = time;
- healer.SendFlags |= 1;
++ entity orb = nades_spawn_orb(this.owner, this.realowner, this.origin, autocvar_g_nades_heal_time, autocvar_g_nades_nade_radius);
+
- healer.touch = nade_heal_touch;
- healer.colormod = '1 0 0';
++ settouch(orb, nade_heal_touch);
++ orb.colormod = '1 0 0';
}
- void nade_monster_boom()
- {SELFPARAM();
- entity e = spawnmonster(self.pokenade_type, 0, self.realowner, self.realowner, self.origin, false, false, 1);
+ void nade_monster_boom(entity this)
+ {
+ entity e = spawnmonster(this.pokenade_type, 0, this.realowner, this.realowner, this.origin, false, false, 1);
if(autocvar_g_nades_pokenade_monster_lifetime > 0)
e.monster_lifetime = time + autocvar_g_nades_pokenade_monster_lifetime;
expef = EFFECT_SPAWN_RED;
break;
+ case NADE_TYPE_ENTRAP:
+ nade_blast = false;
+ expef = EFFECT_SPAWN_YELLOW;
+ break;
+
default:
case NADE_TYPE_NORMAL:
- expef = EFFECT_NADE_EXPLODE(self.realowner.team);
+ expef = EFFECT_NADE_EXPLODE(this.realowner.team);
break;
}
if(nade_blast)
{
- RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
- autocvar_g_nades_nade_radius, self, world, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy);
- Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self);
+ RadiusDamage(this, this.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
+ autocvar_g_nades_nade_radius, this, world, autocvar_g_nades_nade_force, this.projectiledeathtype, this.enemy);
+ Damage_DamageInfo(this.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, this.projectiledeathtype, 0, this);
}
- if(self.takedamage)
- switch ( Nades_from(self.nade_type) )
+ if(this.takedamage)
+ switch ( Nades_from(this.nade_type) )
{
- case NADE_TYPE_NAPALM: nade_napalm_boom(); break;
- case NADE_TYPE_ICE: nade_ice_boom(); break;
- case NADE_TYPE_TRANSLOCATE: nade_translocate_boom(); break;
- case NADE_TYPE_SPAWN: nade_spawn_boom(); break;
- case NADE_TYPE_HEAL: nade_heal_boom(self); break;
- case NADE_TYPE_MONSTER: nade_monster_boom(); break;
- case NADE_TYPE_ENTRAP: nade_entrap_boom(self); break;
+ case NADE_TYPE_NAPALM: nade_napalm_boom(this); break;
+ case NADE_TYPE_ICE: nade_ice_boom(this); break;
+ case NADE_TYPE_TRANSLOCATE: nade_translocate_boom(this); break;
+ case NADE_TYPE_SPAWN: nade_spawn_boom(this); break;
+ case NADE_TYPE_HEAL: nade_heal_boom(this); break;
+ case NADE_TYPE_MONSTER: nade_monster_boom(this); break;
++ case NADE_TYPE_ENTRAP: nade_entrap_boom(this); break;
}
- FOREACH_ENTITY_ENT(aiment, self,
+ FOREACH_ENTITY_ENT(aiment, this,
{
if(it.classname == "grapplinghook")
RemoveGrapplingHook(it.realowner);
}
FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, LAMBDA(
- other.revive_progress = self.revive_progress;
- other.reviving = false;
+ it.revive_progress = player.revive_progress;
+ it.reviving = false;
));
}
-
- return false;
}
- {SELFPARAM();
- if (STAT(ENTRAP_ORB, this) > time)
+MUTATOR_HOOKFUNCTION(nades, PlayerPhysics)
- this.stat_sv_maxspeed *= autocvar_g_nades_entrap_speed;
- this.stat_sv_airspeedlimit_nonqw *= autocvar_g_nades_entrap_speed;
++{
++ entity player = M_ARGV(0, entity);
++
++ if (STAT(ENTRAP_ORB, player) > time)
+ {
- return false;
++ player.stat_sv_maxspeed *= autocvar_g_nades_entrap_speed;
++ player.stat_sv_airspeedlimit_nonqw *= autocvar_g_nades_entrap_speed;
+ }
+}
+
MUTATOR_HOOKFUNCTION(nades, PlayerSpawn)
- {SELFPARAM();
+ {
+ entity player = M_ARGV(0, entity);
+
if(autocvar_g_nades_spawn)
- self.nade_refire = time + autocvar_g_spawnshieldtime;
+ player.nade_refire = time + autocvar_g_spawnshieldtime;
else
- self.nade_refire = time + autocvar_g_nades_nade_refire;
+ player.nade_refire = time + autocvar_g_nades_nade_refire;
if(autocvar_g_nades_bonus_client_select)
- self.nade_type = self.cvar_cl_nade_type;
+ player.nade_type = player.cvar_cl_nade_type;
- self.nade_timer = 0;
+ player.nade_timer = 0;
- if (!self.offhand) self.offhand = OFFHAND_NADE;
+ if (!player.offhand) player.offhand = OFFHAND_NADE;
- if(self.nade_spawnloc)
+ if(player.nade_spawnloc)
{
- setorigin(self, self.nade_spawnloc.origin);
- self.nade_spawnloc.cnt -= 1;
+ setorigin(player, player.nade_spawnloc.origin);
+ player.nade_spawnloc.cnt -= 1;
- if(self.nade_spawnloc.cnt <= 0)
+ if(player.nade_spawnloc.cnt <= 0)
{
- remove(self.nade_spawnloc);
- self.nade_spawnloc = world;
+ remove(player.nade_spawnloc);
+ player.nade_spawnloc = world;
}
}
-
- return false;
}
MUTATOR_HOOKFUNCTION(nades, PlayerDies, CBC_ORDER_LAST)
MUTATOR_HOOKFUNCTION(nades, DropSpecialItems)
{
+ entity frag_target = M_ARGV(0, entity);
+
if(frag_target.nade)
toss_nade(frag_target, true, '0 0 0', time + 0.05);
-
- return false;
}
- bool nades_RemovePlayer()
- {SELFPARAM();
- nades_Clear(self);
- nades_RemoveBonus(self);
- return false;
+ void nades_RemovePlayer(entity this)
+ {
+ nades_Clear(this);
+ nades_RemoveBonus(this);
}
- MUTATOR_HOOKFUNCTION(nades, MakePlayerObserver) { nades_RemovePlayer(); }
- MUTATOR_HOOKFUNCTION(nades, ClientDisconnect) { nades_RemovePlayer(); }
- MUTATOR_HOOKFUNCTION(nades, reset_map_global) { nades_RemovePlayer(); }
+ MUTATOR_HOOKFUNCTION(nades, MakePlayerObserver) { entity player = M_ARGV(0, entity); nades_RemovePlayer(player); }
+ MUTATOR_HOOKFUNCTION(nades, ClientDisconnect) { entity player = M_ARGV(0, entity); nades_RemovePlayer(player); }
+ MUTATOR_HOOKFUNCTION(nades, reset_map_global)
+ {
+ FOREACH_CLIENT(IS_PLAYER(it),
+ {
+ nades_RemovePlayer(it);
+ });
+ }
MUTATOR_HOOKFUNCTION(nades, SpectateCopy)
- {SELFPARAM();
- self.nade_timer = other.nade_timer;
- self.nade_type = other.nade_type;
- self.pokenade_type = other.pokenade_type;
- self.bonus_nades = other.bonus_nades;
- self.bonus_nade_score = other.bonus_nade_score;
- self.stat_healing_orb = other.stat_healing_orb;
- self.stat_healing_orb_alpha = other.stat_healing_orb_alpha;
- STAT(ENTRAP_ORB, this) = STAT(ENTRAP_ORB, other);
- STAT(ENTRAP_ORB_ALPHA, this) = STAT(ENTRAP_ORB_ALPHA, other);
- return false;
+ {
+ entity spectatee = M_ARGV(0, entity);
+ entity client = M_ARGV(1, entity);
+
+ client.nade_timer = spectatee.nade_timer;
+ client.nade_type = spectatee.nade_type;
+ client.pokenade_type = spectatee.pokenade_type;
+ client.bonus_nades = spectatee.bonus_nades;
+ client.bonus_nade_score = spectatee.bonus_nade_score;
+ client.stat_healing_orb = spectatee.stat_healing_orb;
+ client.stat_healing_orb_alpha = spectatee.stat_healing_orb_alpha;
++ STAT(ENTRAP_ORB, client) = STAT(ENTRAP_ORB, spectatee);
++ STAT(ENTRAP_ORB_ALPHA, client) = STAT(ENTRAP_ORB_ALPHA, spectatee);
}
REPLICATE(cvar_cl_nade_type, int, "cl_nade_type");