Merge branch 'master' into Mario/entrap_nade 324/head
authorMario <mario@smbclan.net>
Tue, 14 Jun 2016 12:58:50 +0000 (22:58 +1000)
committerMario <mario@smbclan.net>
Tue, 14 Jun 2016 12:58:50 +0000 (22:58 +1000)
15 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/shield.md3_0.skin [new file with mode: 0644]
models/ctf/shield.md3_1.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
scripts/nades.shader [new file with mode: 0644]
scripts/shaderlist.txt
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/shield.md3_0.skin b/models/ctf/shield.md3_0.skin
new file mode 100644 (file)
index 0000000..113f275
--- /dev/null
@@ -0,0 +1 @@
+shield,ons_shield
diff --git a/models/ctf/shield.md3_1.skin b/models/ctf/shield.md3_1.skin
new file mode 100644 (file)
index 0000000..bfeddf2
--- /dev/null
@@ -0,0 +1 @@
+shield,nade_orb
index 0f49665424d3d5a0f8af9bdaa483bb088baa1525..7910786107c1685dd05f2e896ea65d976a870607 100644 (file)
@@ -197,7 +197,7 @@ set g_nades_nade_edgedamage 90
 set g_nades_nade_radius 300
 set g_nades_nade_force 650
 set g_nades_nade_newton_style 0
-set g_nades_nade_type 1 "Type of the off-hand grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade"
+set g_nades_nade_type 1 "Type of the off-hand grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade 8:entrap"
 
 seta cl_nade_timer 1 "show a visual timer for nades, 1 = only circle, 2 = circle with text"
 seta cl_nade_type 3
@@ -215,7 +215,7 @@ seta cl_pokenade_type "zombie"
 //
 set g_nades_bonus 0 "Enable bonus grenades"
 set g_nades_bonus_client_select 0 "Allow client side selection of bonus nade type"
-set g_nades_bonus_type 2 "Type of the bonus grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade"
+set g_nades_bonus_type 2 "Type of the bonus grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade 8:entrap"
 set g_nades_bonus_onstrength 1 "Always give bonus grenades to players that have the strength powerup"
 set g_nades_bonus_max 3 "Maximum number of bonus grenades"
 set g_nades_bonus_only 0 "Disallow regular nades, only bonus nades can be used"
@@ -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 08aeaaeb7ac975de25bd2c591427d8c3dc28cb99..f47d8e7c5afdd76ea2ce79630d28a11e4ee608e6 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/ctf/shield.md3");
 
 MODEL(GIB_CHUNK,                        "models/gibs/chunk.mdl");
 MODEL(GIB_LEG1,                         "models/gibs/leg1.md3");
index d2f350c5f2bcaa3a9dcba264a541f84c305ff700..8a7337f6103a9020849196832b0e24484f9d21be 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 c704d31ae2ef03872201b8655594375b8957f118..1d5a8c37b38b2bf9f167bf041830a957dabb5bbd 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;
-       M_ARGV(0, vector) = NADE_TYPE_HEAL.m_color;
-       M_ARGV(1, float) = STAT(HEALING_ORB_ALPHA);
-       return true;
+       if (STAT(HEALING_ORB) > time)
+       {
+               M_ARGV(0, vector) = NADE_TYPE_HEAL.m_color;
+               M_ARGV(1, float) = STAT(HEALING_ORB_ALPHA);
+               return true;
+       }
+       if (STAT(ENTRAP_ORB) > time)
+       {
+               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)
 {
@@ -503,7 +512,7 @@ void nade_spawn_boom(entity this)
        this.realowner.nade_spawnloc = spawnloc;
 }
 
-void nade_heal_think(entity this)
+void nades_orb_think(entity this)
 {
        if(time >= this.ltime)
        {
@@ -522,6 +531,79 @@ void nade_heal_think(entity this)
                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.skin = 1;
+       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;
+
+       setthink(orb, nades_orb_think);
+       orb.nextthink = time;
+
+       return orb;
+}
+
+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) || IS_MONSTER(other) )
+       {
+               entity show_tint = (IS_VEHICLE(other)) ? other.owner : other;
+               STAT(ENTRAP_ORB, show_tint) = time + 0.1;
+
+               float tint_alpha = 0.75;
+               if(SAME_TEAM(other, this.realowner))
+                       tint_alpha = 0.45;
+               STAT(ENTRAP_ORB_ALPHA, show_tint) = tint_alpha * (this.ltime - time) / this.orb_lifetime;
+       }
+}
+
+void nade_entrap_boom(entity this)
+{
+       entity orb = nades_spawn_orb(this.owner, this.realowner, this.origin, autocvar_g_nades_entrap_time, autocvar_g_nades_entrap_radius);
+
+       settouch(orb, nade_entrap_touch);
+       orb.colormod = NADE_TYPE_ENTRAP.m_color;
+}
+
 void nade_heal_touch(entity this)
 {
        float maxhealth;
@@ -560,34 +642,16 @@ void nade_heal_touch(entity this)
        {
                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 * (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;
-       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);
+
+       settouch(orb, nade_heal_touch);
+       orb.colormod = '1 0 0';
 }
 
 void nade_monster_boom(entity this)
@@ -634,6 +698,11 @@ void nade_boom(entity this)
                        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(this.realowner.team);
@@ -664,6 +733,7 @@ void nade_boom(entity this)
                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, this,
@@ -1239,6 +1309,28 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
        }
 }
 
+MUTATOR_HOOKFUNCTION(nades, PlayerPhysics)
+{
+       entity player = M_ARGV(0, entity);
+
+       if (STAT(ENTRAP_ORB, player) > time)
+       {
+               player.stat_sv_maxspeed *= autocvar_g_nades_entrap_speed;
+               player.stat_sv_airspeedlimit_nonqw *= autocvar_g_nades_entrap_speed;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(nades, MonsterMove)
+{
+    entity mon = M_ARGV(0, entity);
+
+       if (STAT(ENTRAP_ORB, mon) > time)
+       {
+               M_ARGV(1, float) *= autocvar_g_nades_entrap_speed; // run speed
+               M_ARGV(2, float) *= autocvar_g_nades_entrap_speed; // walk speed
+       }
+}
+
 MUTATOR_HOOKFUNCTION(nades, PlayerSpawn)
 {
        entity player = M_ARGV(0, entity);
@@ -1373,6 +1465,8 @@ MUTATOR_HOOKFUNCTION(nades, SpectateCopy)
        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");
index 851b4a539d949fa9349723d919c4c055ab9b94eb..2f48d9579cba95cfb8272464fc3a8df0f54433f2 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 70f2218e72148e4dff4f3a17463aaac5a86703f5..af320d9c15555c866f30505e72dee4d0c41c237a 100644 (file)
@@ -4,76 +4,84 @@
 
 #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;
+       this.angles = this.angles + dt * this.avelocity;
 }
 
-void healer_setup(entity e)
+void orb_setup(entity e)
 {
-       setmodel(e, MDL_NADE_HEAL);
+       setmodel(e, MDL_NADE_ORB);
+       e.skin = 1;
 
        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 f5eec57658a0bde68e47ad440ed69489921631c1..2c471f0db30bb63d39b53966ed92ff6bf2e573ad 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 c565298e8f509988b2e6c3d58d2888cda1e6e38a..314858780bf7f6917035c71a10c89f66e7bd7ecb 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 = 0.01;
+float autocvar_g_nades_entrap_speed = 0.5;
+float autocvar_g_nades_entrap_radius = 500;
+float autocvar_g_nades_entrap_time = 10;
 string autocvar_g_nades_pokenade_monster_type;
 float autocvar_g_nades_pokenade_monster_lifetime;
 bool autocvar_g_jump_grunt;
diff --git a/scripts/nades.shader b/scripts/nades.shader
new file mode 100644 (file)
index 0000000..0ed8b42
--- /dev/null
@@ -0,0 +1,13 @@
+nade_orb
+{
+       cull none
+       dpnoshadow
+       surfaceparm nolightmap
+
+ {
+       map textures/nade_orb
+       blendfunc add
+       tcMod stretch 0 0.25
+       rgbGen lightingDiffuse
+ }
+}
index ce11875b7ba04f75bb4eb280631d09b142885f2d..0a391e6b697384621a9417557652b6ffbec2ef8d 100644 (file)
@@ -16,3 +16,4 @@ turrets
 weapons
 monsters
 ok_nade_counter
+nades
diff --git a/textures/nade_orb.tga b/textures/nade_orb.tga
new file mode 100644 (file)
index 0000000..7106856
Binary files /dev/null and b/textures/nade_orb.tga differ