]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/mutators/gamemode_freezetag.qc
freezetag: add a "revivals" scoreboard column; calculate "score"
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / gamemode_freezetag.qc
index 14fe430f1209b8cc6496eddb165d497864b3d15f..27b06ec73656d50537cebc888d42d30ce5342c46 100644 (file)
@@ -1,7 +1,8 @@
 void freezetag_Initialize()
 {
        precache_model("models/ice/ice.md3");
-       warmup = time + cvar("g_start_delay") + cvar("g_freezetag_warmup");
+       warmup = time + autocvar_g_start_delay + autocvar_g_freezetag_warmup;
+       ScoreRules_freezetag();
 }
 
 void freezetag_CheckWinner()
@@ -9,7 +10,7 @@ void freezetag_CheckWinner()
        if(time <= game_starttime) // game didn't even start yet! nobody can win in that case.
                return;
 
-       if(next_round || (time > warmup - cvar("g_freezetag_warmup") && time < warmup))
+       if(next_round || (time > warmup - autocvar_g_freezetag_warmup && time < warmup))
                return; // already waiting for next round to start
 
        if((redalive >= 1 && bluealive >= 1) // counted in arena.qc
@@ -52,13 +53,16 @@ void freezetag_CheckWinner()
        next_round = time + 5;
 }
 
+// this is needed to allow the player to turn his view around (fixangle can't
+// be used to freeze his view, as that also changes the angles), while not
+// turning that ice object with the player
 void freezetag_Ice_Think()
 {
        setorigin(self, self.owner.origin - '0 0 16');
        self.nextthink = time;
 }
 
-void freezetag_Freeze()
+void freezetag_Freeze(entity attacker)
 {
        self.freezetag_frozen = 1;
 
@@ -71,7 +75,11 @@ void freezetag_Freeze()
        ice.frame = floor(random() * 21); // ice model has 20 different looking frames
        setmodel(ice, "models/ice/ice.md3");
 
-       self.movement = '0 0 0';
+       entity oldself;
+       oldself = self;
+       self = ice;
+       freezetag_Ice_Think();
+       self = oldself;
 
        // add waypoint
        WaypointSprite_Spawn("freezetag_frozen", 0, 0, self, '0 0 64', world, self.team, self, waypointsprite_attached, TRUE);
@@ -79,12 +87,33 @@ void freezetag_Freeze()
        {
                WaypointSprite_UpdateTeamRadar(self.waypointsprite_attached, RADARICON_WAYPOINT, '0.25 0.90 1');
        }
+
+       if(attacker == self)
+       {
+               // you froze your own dumb self
+               // counted as "suicide" already
+               PlayerScore_Add(self, SP_SCORE, -1);
+       }
+       else if(attacker.classname == "player")
+       {
+               // got frozen by an enemy
+               // counted as "kill" and "death" already
+               PlayerScore_Add(self, SP_SCORE, -1);
+               PlayerScore_Add(attacker, SP_SCORE, +1);
+       }
+       else
+       {
+               // nothing - got frozen by the game type rules themselves
+       }
 }
 
-void freezetag_Unfreeze()
+void freezetag_Unfreeze(entity attacker)
 {
        self.freezetag_frozen = 0;
 
+       PlayerScore_Add(attacker, SP_FREEZETAG_REVIVAL, +1);
+       PlayerScore_Add(attacker, SP_SCORE, +1);
+
        // remove the ice block
        entity ice;
        for(ice = world; (ice = find(ice, classname, "freezetag_ice")); ) if(ice.owner == self)
@@ -134,23 +163,27 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerDies)
                else if(self.team == COLOR_TEAM4)
                        --pinkalive;
                --totalalive;
+
+        freezetag_Freeze(frag_attacker);
        }
 
-       freezetag_Freeze();
+    if(frag_attacker.classname == STR_PLAYER)
+        centerprint(frag_attacker, strcat("^2You froze ^7", frag_target.netname, ".\n"));
 
-       centerprint(frag_attacker, strcat("^2You froze ^7", frag_target.netname, ".\n"));
        if(frag_attacker == frag_target || frag_attacker == world)
        {
-               centerprint(frag_target, "^1You froze yourself.\n");
+        if(frag_target.classname == STR_PLAYER)
+            centerprint(frag_target, "^1You froze yourself.\n");
                bprint("^7", frag_target.netname, "^1 froze himself.\n");
        }
        else
        {
-               centerprint(frag_target, strcat("^1You were frozen by ^7", frag_attacker.netname, ".\n"));
+        if(frag_target.classname == STR_PLAYER)
+            centerprint(frag_target, strcat("^1You were frozen by ^7", frag_attacker.netname, ".\n"));
                bprint("^7", frag_target.netname, "^1 was frozen by ^7", frag_attacker.netname, ".\n");
        }
 
-       frag_target.health = cvar("g_balance_health_start"); // "respawn" the player :P
+       frag_target.health = autocvar_g_balance_health_start; // "respawn" the player :P
 
        freezetag_CheckWinner();
 
@@ -159,8 +192,10 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerDies)
 
 MUTATOR_HOOKFUNCTION(freezetag_PlayerSpawn)
 {
+    freezetag_Unfreeze(); // start by making sure that all ice blocks are removed
+
        if(totalspawned == 1 && time > game_starttime) // only one player active on server, start a new match immediately
-       if(!next_round && warmup && (time < warmup - cvar("g_freezetag_warmup") || time > warmup)) // not awaiting next round
+       if(!next_round && warmup && (time < warmup - autocvar_g_freezetag_warmup || time > warmup)) // not awaiting next round
        {
                next_round = time;
                return 1;
@@ -168,11 +203,7 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerSpawn)
        if(warmup && time > warmup) // spawn too late, freeze player
        {
                centerprint(self, "^1You spawned after the round started, you'll spawn as frozen.\n");
-               freezetag_Freeze();
-       }
-       else // we are still in the delay period before the round starts
-       {
-               freezetag_Unfreeze();
+               freezetag_Freeze(world);
        }
 
        return 1;
@@ -186,54 +217,64 @@ MUTATOR_HOOKFUNCTION(freezetag_GiveFragsForKill)
 
 MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink)
 {
-       vector revive_extra_size;
-       revive_extra_size = '1 1 1' * cvar("g_freezetag_revive_extra_size");
-
-       float teammate_nearby;
-       FOR_EACH_PLAYER(other) if(self != other)
-       {
-               if(other.freezetag_frozen == 0)
-               {
-                       if(other.team == self.team)
-                       {
-                               teammate_nearby = boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax);
-                               if(teammate_nearby)
-                                       break;
-                       }
-               }
-       }
-
-       if(teammate_nearby && self.freezetag_frozen == 1)
-       {
-               if(self.freezetag_beginrevive_time == -9999)
-               {
-                       self.freezetag_beginrevive_time = time;
-                       self.freezetag_revive_progress = 0;
-                       other.freezetag_revive_progress = 0;
-               }
-               else
-               {
-                       self.freezetag_revive_progress = (time - self.freezetag_beginrevive_time) / cvar("g_freezetag_revive_time");
-                       other.freezetag_revive_progress = (time - self.freezetag_beginrevive_time) / cvar("g_freezetag_revive_time");
-                       if(time - self.freezetag_beginrevive_time >= cvar("g_freezetag_revive_time"))
-                       {
-                               freezetag_Unfreeze();
-
-                               centerprint(self, strcat("^5You were revived by ^7", other.netname, ".\n"));
-                               centerprint(other, strcat("^5You revived ^7", self.netname, ".\n"));
-                               bprint("^7", other.netname, "^5 revived ^7", self.netname, ".\n");
-
-                               self.freezetag_beginrevive_time = -9999;
-                               self.freezetag_revive_progress = 0;
-                               other.freezetag_revive_progress = 0;
-                       }
-               }
-       }
-       else if(!teammate_nearby) // only if no teammate is nearby will we reset
-       {
-               self.freezetag_beginrevive_time = -9999;
-               self.freezetag_revive_progress = 0;
-       }
+    vector revive_extra_size;
+    revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
+
+    float teammate_nearby;
+    FOR_EACH_PLAYER(other) if(self != other)
+    {
+        if(other.freezetag_frozen == 0)
+        {
+            if(other.team == self.team)
+            {
+                teammate_nearby = boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax);
+                if(teammate_nearby)
+                    break;
+            }
+        }
+    }
+
+    if(teammate_nearby && self.freezetag_frozen == 1) // OK, there is at least one teammate reviving us
+    {
+        if(self.freezetag_beginrevive_time == -9999) // initialize values if this is the first frame of revival
+        {
+            self.freezetag_beginrevive_time = time;
+            self.freezetag_revive_progress = 0;
+        }
+        else
+        {
+            self.freezetag_revive_progress = (time - self.freezetag_beginrevive_time) / autocvar_g_freezetag_revive_time;
+            if(time - self.freezetag_beginrevive_time >= autocvar_g_freezetag_revive_time)
+            {
+                freezetag_Unfreeze();
+
+                centerprint(self, strcat("^5You were revived by ^7", other.netname, ".\n"));
+                centerprint(other, strcat("^5You revived ^7", self.netname, ".\n"));
+                bprint("^7", other.netname, "^5 revived ^7", self.netname, ".\n");
+
+                self.freezetag_beginrevive_time = -9999;
+                self.freezetag_revive_progress = 0;
+            }
+        }
+        // now find EVERY teammate within reviving radius, set their revive_progress values correct
+        FOR_EACH_PLAYER(other) if(self != other)
+        {
+            if(other.freezetag_frozen == 0)
+            {
+                if(other.team == self.team)
+                {
+                    teammate_nearby = boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax);
+                    if(teammate_nearby)
+                        other.freezetag_revive_progress = self.freezetag_revive_progress;
+                }
+            }
+        }
+    }
+    else if(!teammate_nearby) // only if no teammate is nearby will we reset
+    {
+        self.freezetag_beginrevive_time = -9999;
+        self.freezetag_revive_progress = 0;
+    }
 
        return 1;
 }
@@ -241,10 +282,26 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink)
 MUTATOR_HOOKFUNCTION(freezetag_PlayerPhysics)
 {
        if(self.freezetag_frozen)
+       {
                self.movement = '0 0 0';
+               self.disableclientprediction = 1;
+       }
        return 1;
 }
 
+MUTATOR_HOOKFUNCTION(freezetag_PlayerDamage_Calculate)
+{
+    if(g_freezetag)
+    {
+        if(frag_target.freezetag_frozen == 1 && frag_deathtype != DEATH_HURTTRIGGER)
+        {
+            frag_damage = 0;
+            frag_force = frag_force * autocvar_g_freezetag_frozen_force;
+        }
+    }
+    return 1;
+}
+
 MUTATOR_DEFINITION(gamemode_freezetag)
 {
        MUTATOR_HOOK(MakePlayerObserver, freezetag_RemovePlayer, CBC_ORDER_ANY);
@@ -254,6 +311,7 @@ MUTATOR_DEFINITION(gamemode_freezetag)
        MUTATOR_HOOK(GiveFragsForKill, freezetag_GiveFragsForKill, CBC_ORDER_FIRST);
        MUTATOR_HOOK(PlayerPreThink, freezetag_PlayerPreThink, CBC_ORDER_FIRST);
        MUTATOR_HOOK(PlayerPhysics, freezetag_PlayerPhysics, CBC_ORDER_FIRST);
+       MUTATOR_HOOK(PlayerDamage_Calculate, freezetag_PlayerDamage_Calculate, CBC_ORDER_ANY);
 
        MUTATOR_ONADD
        {