New nade type: Entrap (spawns a large orb for 10 seconds that slows down any enemies...
authorMario <mario@smbclan.net>
Sun, 8 May 2016 18:29:54 +0000 (04:29 +1000)
committerMario <mario@smbclan.net>
Sun, 8 May 2016 18:29:54 +0000 (04:29 +1000)
14 files changed:
gfx/hud/default/nade_entrap.tga [new file with mode: 0644]
gfx/hud/luma/nade_entrap.tga [new file with mode: 0644]
models/ctf/orb.md3_0.skin [new file with mode: 0644]
models/nades/orb.md3 [new file with mode: 0644]
models/nades/orb.md3_0.skin [new file with mode: 0644]
mutators.cfg
qcsrc/common/models/all.inc
qcsrc/common/mutators/mutator/nades/nades.inc
qcsrc/common/mutators/mutator/nades/nades.qc
qcsrc/common/mutators/mutator/nades/nades.qh
qcsrc/common/mutators/mutator/nades/net.qc
qcsrc/common/stats.qh
qcsrc/server/autocvars.qh
textures/nade_orb.tga [new file with mode: 0644]

diff --git a/gfx/hud/default/nade_entrap.tga b/gfx/hud/default/nade_entrap.tga
new file mode 100644 (file)
index 0000000..358dc1a
Binary files /dev/null and b/gfx/hud/default/nade_entrap.tga differ
diff --git a/gfx/hud/luma/nade_entrap.tga b/gfx/hud/luma/nade_entrap.tga
new file mode 100644 (file)
index 0000000..27287ad
Binary files /dev/null and b/gfx/hud/luma/nade_entrap.tga differ
diff --git a/models/ctf/orb.md3_0.skin b/models/ctf/orb.md3_0.skin
new file mode 100644 (file)
index 0000000..89de359
--- /dev/null
@@ -0,0 +1 @@
+ons_shield,nade_orb
diff --git a/models/nades/orb.md3 b/models/nades/orb.md3
new file mode 100644 (file)
index 0000000..22d7bcc
Binary files /dev/null and b/models/nades/orb.md3 differ
diff --git a/models/nades/orb.md3_0.skin b/models/nades/orb.md3_0.skin
new file mode 100644 (file)
index 0000000..bfeddf2
--- /dev/null
@@ -0,0 +1 @@
+shield,nade_orb
index 0f49665..3078379 100644 (file)
@@ -267,6 +267,12 @@ set g_nades_heal_foe   -2 "Multiplier of health given to enemies"
 set g_nades_pokenade_monster_lifetime 150 "How long pokenade monster will survive"
 set g_nades_pokenade_monster_type "zombie" "Monster to spawn"
 
+// Entrap (8)
+set g_nades_entrap_strength 0.01 "Strength of the orb's movement slowing powers"
+set g_nades_entrap_speed 0.5 "Running speed while entrapped"
+set g_nades_entrap_time 10 "Life time of the orb"
+set g_nades_entrap_radius 500
+
 
 // ============
 //  camp check
index 08aeaae..e2a278e 100644 (file)
@@ -125,7 +125,7 @@ MODEL(PROJECTILE_ROCKETMINSTA_LASER,    "models/elaser.mdl");
 MODEL(PROJECTILE_NADE,                  W_Model("v_ok_grenade.md3"));
 MODEL(NADE_VIEW,                        W_Model("h_ok_grenade.iqm"));
 MODEL(NADE_TIMER,                       "models/ok_nade_counter/ok_nade_counter.md3");
-MODEL(NADE_HEAL,                        "models/ctf/shield.md3");
+MODEL(NADE_ORB,                         "models/nades/orb.md3");
 
 MODEL(GIB_CHUNK,                        "models/gibs/chunk.mdl");
 MODEL(GIB_LEG1,                         "models/gibs/leg1.md3");
index d2f350c..8a7337f 100644 (file)
@@ -60,3 +60,11 @@ REGISTER_NADE(MONSTER) {
     NADE_PROJECTILE(0, PROJECTILE_NADE_MONSTER, EFFECT_NADE_TRAIL_RED);
     NADE_PROJECTILE(1, PROJECTILE_NADE_MONSTER_BURN, EFFECT_NADE_TRAIL_BURN_RED);
 }
+
+REGISTER_NADE(ENTRAP) {
+    this.m_color = '0.15 0.85 0';
+    this.m_name = _("Entrap grenade");
+    this.m_icon = "nade_entrap";
+    NADE_PROJECTILE(0, PROJECTILE_NADE_ENTRAP, EFFECT_NADE_TRAIL_YELLOW);
+    NADE_PROJECTILE(1, PROJECTILE_NADE_ENTRAP_BURN, EFFECT_NADE_TRAIL_BURN_YELLOW);
+}
index cabfd31..ab4e2bc 100644 (file)
@@ -38,10 +38,19 @@ entity Nade_TrailEffect(int proj, int nade_team)
 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;
+       if (STAT(HEALING_ORB) > time)
+       {
+               MUTATOR_ARGV(0, vector) = NADE_TYPE_HEAL.m_color;
+               MUTATOR_ARGV(0, 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);
+               return true;
+       }
+       return false;
 }
 MUTATOR_HOOKFUNCTION(cl_nades, Ent_Projectile)
 {
@@ -502,23 +511,91 @@ void nade_spawn_boom()
        self.realowner.nade_spawnloc = spawnloc;
 }
 
-void nade_heal_think()
+void nades_orb_think()
 {SELFPARAM();
-       if(time >= self.ltime)
+       if(time >= this.ltime)
        {
-               remove(self);
+               remove(this);
                return;
        }
 
-       self.nextthink = time;
+       this.nextthink = time;
 
-       if(time >= self.nade_special_time)
+       if(time >= this.nade_special_time)
        {
-               self.nade_special_time = time+0.25;
-               self.nade_show_particles = 1;
+               this.nade_special_time = time+0.25;
+               this.nade_show_particles = 1;
        }
        else
-               self.nade_show_particles = 0;
+               this.nade_show_particles = 0;
+}
+
+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;
+
+       orb.think = nades_orb_think;
+       orb.nextthink = time;
+
+       return orb;
+}
+
+void nade_entrap_touch()
+{SELFPARAM();
+       if(DIFF_TEAM(other, self.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;
+                       STAT(ENTRAP_ORB_ALPHA, show_tint) = 0.75 * (self.ltime - time) / self.orb_lifetime;
+               }
+       }
+}
+
+void nade_entrap_boom(entity this)
+{
+       entity healer = nades_spawn_orb(this.owner, this.realowner, this.origin, autocvar_g_nades_entrap_time, autocvar_g_nades_entrap_radius);
+
+       healer.touch = nade_entrap_touch;
+       healer.colormod = NADE_TYPE_ENTRAP.m_color;
 }
 
 void nade_heal_touch()
@@ -559,34 +636,16 @@ void nade_heal_touch()
        {
                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.healer_lifetime;
+               show_red.stat_healing_orb_alpha = 0.75 * (self.ltime - time) / self.orb_lifetime;
        }
 }
 
-void nade_heal_boom()
-{SELFPARAM();
-       entity healer;
-       healer = spawn();
-       healer.owner = self.owner;
-       healer.realowner = self.realowner;
-       setorigin(healer, self.origin);
-       healer.healer_lifetime = autocvar_g_nades_heal_time; // save the cvar
-       healer.ltime = time + healer.healer_lifetime;
-       healer.team = self.realowner.team;
-       healer.bot_dodge = false;
-       healer.solid = SOLID_TRIGGER;
-       healer.touch = 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);
+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);
 
-       healer.think = nade_heal_think;
-       healer.nextthink = time;
-       healer.SendFlags |= 1;
+       healer.touch = nade_heal_touch;
+       healer.colormod = '1 0 0';
 }
 
 void nade_monster_boom()
@@ -633,6 +692,11 @@ void nade_boom()
                        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);
@@ -661,8 +725,9 @@ void nade_boom()
                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(); 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;
        }
 
        FOREACH_ENTITY_ENT(aiment, self,
@@ -1234,6 +1299,16 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
        return false;
 }
 
+MUTATOR_HOOKFUNCTION(nades, PlayerPhysics)
+{SELFPARAM();
+       if (STAT(ENTRAP_ORB, this) > time)
+       {
+               this.stat_sv_maxspeed *= autocvar_g_nades_entrap_speed;
+               this.stat_sv_airspeedlimit_nonqw *= autocvar_g_nades_entrap_speed;
+       }
+       return false;
+}
+
 MUTATOR_HOOKFUNCTION(nades, PlayerSpawn)
 {SELFPARAM();
        if(autocvar_g_nades_spawn)
@@ -1355,6 +1430,8 @@ MUTATOR_HOOKFUNCTION(nades, SpectateCopy)
        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;
 }
 
index da80327..2df7113 100644 (file)
@@ -17,6 +17,8 @@ const int PROJECTILE_NADE_HEAL = 80;
 const int PROJECTILE_NADE_HEAL_BURN = 81;
 const int PROJECTILE_NADE_MONSTER = 82;
 const int PROJECTILE_NADE_MONSTER_BURN = 83;
+const int PROJECTILE_NADE_ENTRAP = 84;
+const int PROJECTILE_NADE_ENTRAP_BURN = 85;
 
 REGISTRY(Nades, BITS(4))
 #define Nades_from(i) _Nades_from(i, NADE_TYPE_Null)
@@ -56,8 +58,8 @@ Nade Nade_FromProjectile(int proj)
 
 #include "nades.inc"
 
-.float healer_lifetime;
-.float healer_radius;
+.float orb_lifetime;
+.float orb_radius;
 
 #ifdef SVQC
 
@@ -78,7 +80,7 @@ Nade Nade_FromProjectile(int proj)
 .float stat_healing_orb_alpha = _STAT(HEALING_ORB_ALPHA);
 .float nade_show_particles;
 
-bool healer_send(entity this, entity to, int sf);
+bool orb_send(entity this, entity to, int sf);
 
 // Remove nades that are being thrown
 void nades_Clear(entity player);
index 70f2218..269574c 100644 (file)
@@ -4,76 +4,82 @@
 
 #ifdef CSQC
 .float ltime;
-void healer_draw(entity this)
+void orb_draw(entity this)
 {
        float dt = time - this.move_time;
        this.move_time = time;
        if(dt <= 0)
                return;
 
-       this.alpha = (this.ltime - time) / this.healer_lifetime;
-       this.scale = min((1 - this.alpha)*this.healer_lifetime*4,1)*this.healer_radius;
+       this.alpha = (this.ltime - time) / this.orb_lifetime;
+       this.scale = min((1 - this.alpha)*this.orb_lifetime*4,1)*this.orb_radius;
 }
 
-void healer_setup(entity e)
+void orb_setup(entity e)
 {
-       setmodel(e, MDL_NADE_HEAL);
+       setmodel(e, MDL_NADE_ORB);
 
        setorigin(e, e.origin);
 
        float model_radius = e.maxs.x;
-       vector size = '1 1 1' * e.healer_radius / 2;
+       vector size = '1 1 1' * e.orb_radius / 2;
        setsize(e,-size,size);
-       e.healer_radius = e.healer_radius/model_radius*0.6;
+       e.orb_radius = e.orb_radius/model_radius*0.6;
 
-       e.draw = healer_draw;
+       e.draw = orb_draw;
        e.health = 255;
        e.movetype = MOVETYPE_NONE;
        e.solid = SOLID_NOT;
        e.drawmask = MASK_NORMAL;
        e.scale = 0.01;
        e.avelocity = e.move_avelocity = '7 0 11';
-       e.colormod = '1 0 0';
        e.renderflags |= RF_ADDITIVE;
 }
 #endif
 
-REGISTER_NET_LINKED(Nade_Heal)
+REGISTER_NET_LINKED(Nade_Orb)
 
 #ifdef CSQC
-NET_HANDLE(Nade_Heal, bool isNew)
+NET_HANDLE(Nade_Orb, bool isNew)
 {
-       Net_Accept(Nade_Heal);
+       Net_Accept(Nade_Orb);
        int sf = ReadByte();
        if (sf & 1) {
                this.origin_x = ReadCoord();
                this.origin_y = ReadCoord();
                this.origin_z = ReadCoord();
                setorigin(this, this.origin);
-               this.healer_lifetime = ReadByte();
-               this.healer_radius = ReadShort();
+               this.colormod_x = ReadCoord();
+               this.colormod_y = ReadCoord();
+               this.colormod_z = ReadCoord();
+               this.orb_lifetime = ReadByte();
+               this.orb_radius = ReadShort();
                this.ltime = time + ReadByte()/10.0;
-               // this.ltime = time + this.healer_lifetime;
-               healer_setup(this);
+               // this.ltime = time + this.orb_lifetime;
+               orb_setup(this);
        }
        return true;
 }
 #endif
 
 #ifdef SVQC
-bool healer_send(entity this, entity to, int sf)
+bool orb_send(entity this, entity to, int sf)
 {
        int channel = MSG_ENTITY;
-       WriteHeader(channel, Nade_Heal);
+       WriteHeader(channel, Nade_Orb);
        WriteByte(channel, sf);
        if (sf & 1) {
                WriteCoord(channel, this.origin.x);
                WriteCoord(channel, this.origin.y);
                WriteCoord(channel, this.origin.z);
 
-               WriteByte(channel, this.healer_lifetime);
+               WriteCoord(channel, this.colormod.x);
+               WriteCoord(channel, this.colormod.y);
+               WriteCoord(channel, this.colormod.z);
+
+               WriteByte(channel, this.orb_lifetime);
                //WriteByte(MSG_ENTITY, this.ltime - time + 1);
-               WriteShort(channel, this.healer_radius);
+               WriteShort(channel, this.orb_radius);
                // round time delta to a 1/10th of a second
                WriteByte(channel, (this.ltime - time)*10.0+0.5);
        }
index e9828c6..54a76b3 100644 (file)
@@ -122,6 +122,8 @@ REGISTER_STAT(REVIVE_PROGRESS, float)
 REGISTER_STAT(ROUNDLOST, int)
 REGISTER_STAT(BUFF_TIME, float)
 REGISTER_STAT(CTF_FLAGSTATUS, int)
+REGISTER_STAT(ENTRAP_ORB, float)
+REGISTER_STAT(ENTRAP_ORB_ALPHA, float)
 
 #ifdef SVQC
 int autocvar_g_multijump;
index c565298..d8345f6 100644 (file)
@@ -517,6 +517,10 @@ float autocvar_g_nades_heal_time;
 float autocvar_g_nades_heal_rate;
 float autocvar_g_nades_heal_friend;
 float autocvar_g_nades_heal_foe;
+float autocvar_g_nades_entrap_strength;
+float autocvar_g_nades_entrap_speed;
+float autocvar_g_nades_entrap_radius;
+float autocvar_g_nades_entrap_time;
 string autocvar_g_nades_pokenade_monster_type;
 float autocvar_g_nades_pokenade_monster_lifetime;
 bool autocvar_g_jump_grunt;
diff --git a/textures/nade_orb.tga b/textures/nade_orb.tga
new file mode 100644 (file)
index 0000000..45a97da
Binary files /dev/null and b/textures/nade_orb.tga differ