]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qc
Also don't increase armor and ammo of non-frozen players falling into space too;...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / gamemodes / gamemode / freezetag / sv_freezetag.qc
index 54fac9a5ab0a70a8eb5d4ea57082b3a6719e0015..3bb78272fd0e01a5a2729e7b38423f6cff5c0b90 100644 (file)
@@ -1,7 +1,7 @@
 #include "sv_freezetag.qh"
 
+#include <common/resources/sv_resources.qh>
 #include <server/elimination.qh>
-#include <server/resources.qh>
 
 float autocvar_g_freezetag_frozen_maxtime;
 float autocvar_g_freezetag_revive_clearspeed;
@@ -10,6 +10,15 @@ float autocvar_g_freezetag_round_timelimit;
 int autocvar_g_freezetag_teams_override;
 float autocvar_g_freezetag_warmup;
 
+float autocvar_g_ft_start_health = 100;
+float autocvar_g_ft_start_armor = 100;
+float autocvar_g_ft_start_ammo_shells = 60;
+float autocvar_g_ft_start_ammo_nails = 320;
+float autocvar_g_ft_start_ammo_rockets = 160;
+float autocvar_g_ft_start_ammo_cells = 180;
+float autocvar_g_ft_start_ammo_plasma = 180;
+float autocvar_g_ft_start_ammo_fuel = 0;
+
 void freezetag_count_alive_players()
 {
        total_players = 0;
@@ -31,14 +40,10 @@ void freezetag_count_alive_players()
        });
        FOREACH_CLIENT(IS_REAL_CLIENT(it),
        {
-               STAT(REDALIVE, it) = Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(
-                       1));
-               STAT(BLUEALIVE, it) = Team_GetNumberOfAlivePlayers(
-                       Team_GetTeamFromIndex(2));
-               STAT(YELLOWALIVE, it) = Team_GetNumberOfAlivePlayers(
-                       Team_GetTeamFromIndex(3));
-               STAT(PINKALIVE, it) = Team_GetNumberOfAlivePlayers(
-                       Team_GetTeamFromIndex(4));
+               STAT(REDALIVE, it) = Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(1));
+               STAT(BLUEALIVE, it) = Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(2));
+               STAT(YELLOWALIVE, it) = Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(3));
+               STAT(PINKALIVE, it) = Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(4));
        });
 
        eliminatedPlayers.SendFlags |= 1;
@@ -78,31 +83,6 @@ bool freezetag_CheckTeams()
        return false;
 }
 
-int freezetag_getWinnerTeam()
-{
-       int winner_team = 0;
-       if (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(1)) >= 1)
-       {
-               winner_team = NUM_TEAM_1;
-       }
-       for (int i = 2; i <= NUM_TEAMS; ++i)
-       {
-               if (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) >= 1)
-               {
-                       if (winner_team != 0)
-                       {
-                               return 0;
-                       }
-                       winner_team = Team_IndexToTeam(i);
-               }
-       }
-       if (winner_team)
-       {
-               return winner_team;
-       }
-       return -1; // no player left
-}
-
 void nades_Clear(entity);
 void nades_GiveBonus(entity player, float score);
 
@@ -122,12 +102,10 @@ bool freezetag_CheckWinner()
                return true;
        }
 
-       if (Team_GetNumberOfAliveTeams() > 1)
-       {
+       int winner_team = Team_GetWinnerAliveTeam();
+       if (!winner_team)
                return false;
-       }
 
-       int winner_team = freezetag_getWinnerTeam();
        if(winner_team > 0)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
@@ -373,24 +351,38 @@ MUTATOR_HOOKFUNCTION(ft, PlayerDies)
        frag_target.respawn_time = time + 1;
        frag_target.respawn_flags |= RESPAWN_FORCE;
 
-       // Cases DEATH_TEAMCHANGE and DEATH_AUTOTEAMCHANGE are needed to fix a bug whe
-       // you succeed changing team through the menu: you both really die (gibbing) and get frozen
-       if(ITEM_DAMAGE_NEEDKILL(frag_deathtype)
-               || frag_deathtype == DEATH_TEAMCHANGE.m_id || frag_deathtype == DEATH_AUTOTEAMCHANGE.m_id)
+       // let the player die, they will be automatically frozen when they respawn
+       // it fixes a bug where you both really die (gibbing) and get frozen
+       // if you succeed changing team through the menu
+       if (frag_deathtype == DEATH_TEAMCHANGE.m_id || frag_deathtype == DEATH_AUTOTEAMCHANGE.m_id)
        {
-               // let the player die, he will be automatically frozen when he respawns
-               if (STAT(FROZEN, frag_target) != FROZEN_NORMAL)
-               {
-                       freezetag_Add_Score(frag_target, frag_attacker);
-                       freezetag_count_alive_players();
-                       freezetag_LastPlayerForTeam_Notify(frag_target);
-               }
-               else
-                       Unfreeze(frag_target, false); // remove ice
+               freezetag_Add_Score(frag_target, frag_attacker);
+               freezetag_count_alive_players();
+               freezetag_LastPlayerForTeam_Notify(frag_target);
                frag_target.freezetag_frozen_timeout = -2; // freeze on respawn
                return true;
        }
 
+       if(ITEM_DAMAGE_NEEDKILL(frag_deathtype))
+       {
+               // soft-kill: setting health to something >= 1 after death, ammo won't be reset
+               SetResourceExplicit(frag_target, RES_HEALTH, 1);
+               // restore armor as it was removed in PlayerDamage
+               SetResourceExplicit(frag_target, RES_ARMOR, frag_target.freezetag_frozen_armor);
+
+               // relocate
+               entity spot = SelectSpawnPoint(frag_target, true);
+               setorigin(frag_target, spot.origin);
+               frag_target.oldorigin = frag_target.origin;
+               frag_target.fixangle = true; // turn this way immediately
+               frag_target.angles = vec2(spot.angles);
+               frag_target.velocity = '0 0 0';
+               frag_target.oldvelocity = frag_target.velocity; // prevents fall damage, see CreatureFrame_FallDamage
+               frag_target.avelocity = '0 0 0';
+               frag_target.punchangle = '0 0 0';
+               frag_target.punchvector = '0 0 0';
+       }
+
        if (STAT(FROZEN, frag_target) == FROZEN_NORMAL)
                return true;
 
@@ -418,7 +410,7 @@ MUTATOR_HOOKFUNCTION(ft, PlayerSpawn)
        if(player.freezetag_frozen_timeout == -1) // if PlayerSpawn is called by reset_map_players
                return true; // do nothing, round is starting right now
 
-       if(player.freezetag_frozen_timeout == -2) // player was dead
+       if(player.freezetag_frozen_timeout <= -2) // player was dead
        {
                freezetag_Freeze(player, NULL);
                return true;
@@ -470,6 +462,8 @@ MUTATOR_HOOKFUNCTION(ft, Damage_Calculate)
        //float frag_damage = M_ARGV(4, float);
        vector frag_force = M_ARGV(6, vector);
 
+       frag_target.freezetag_frozen_armor = GetResource(frag_target, RES_ARMOR);
+
        if (STAT(FROZEN, frag_target) == FROZEN_NORMAL && autocvar_g_freezetag_revive_auto_reducible
                && autocvar_g_freezetag_frozen_maxtime > 0 && autocvar_g_freezetag_revive_auto)
        {
@@ -478,7 +472,20 @@ MUTATOR_HOOKFUNCTION(ft, Damage_Calculate)
                        && frag_target.freezetag_frozen_timeout > time)
                {
                        if (fabs(autocvar_g_freezetag_revive_auto_reducible) == 1)
-                               t = vlen(frag_force) * autocvar_g_freezetag_revive_auto_reducible_forcefactor;
+                       {
+                               float maxforce = autocvar_g_freezetag_revive_auto_reducible_maxforce;
+                               t = vlen(frag_force);
+                               // limit hit force considered at once, e.g when you have the Strength
+                               // powerup but also with weapons that fire multiple projectiles at once (crylink)
+                               if (frag_target.freezetag_frozen_force + t > maxforce)
+                               {
+                                       t = max(0, maxforce - frag_target.freezetag_frozen_force);
+                                       frag_target.freezetag_frozen_force = maxforce;
+                               }
+                               else
+                                       frag_target.freezetag_frozen_force += t;
+                               t *= autocvar_g_freezetag_revive_auto_reducible_forcefactor;
+                       }
                        frag_target.freezetag_frozen_timeout -= t;
                        if (frag_target.freezetag_frozen_timeout < time)
                                frag_target.freezetag_frozen_timeout = time;
@@ -508,6 +515,8 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
        //if(player.freezetag_frozen_timeout > 0 && time < player.freezetag_frozen_timeout)
                //player.iceblock.alpha = ICE_MIN_ALPHA + (ICE_MAX_ALPHA - ICE_MIN_ALPHA) * (player.freezetag_frozen_timeout - time) / (player.freezetag_frozen_timeout - player.freezetag_frozen_time);
 
+       player.freezetag_frozen_force = 0;
+
        if (!(frametime && IS_PLAYER(player)))
                return true;
 
@@ -571,22 +580,39 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
        if (!n) // no teammate nearby
        {
                float clearspeed = autocvar_g_freezetag_revive_clearspeed;
-               if (autocvar_g_freezetag_revive_time_to_score > 0)
-                       clearspeed = 0; // prevent stacking points by entering and exiting the revival zone many times
                if (STAT(FROZEN, player) == FROZEN_NORMAL)
-                       STAT(REVIVE_PROGRESS, player) = bound(base_progress, STAT(REVIVE_PROGRESS, player) - frametime * clearspeed * (1 - base_progress), 1);
+               {
+                       if (autocvar_g_freezetag_revive_time_to_score > 0)
+                       {
+                               if (STAT(REVIVE_PROGRESS, player) > base_progress)
+                               {
+                                       // reduce auto-revival time based on manual revival progress
+                                       base_progress = STAT(REVIVE_PROGRESS, player);
+                                       player.freezetag_frozen_timeout = time + autocvar_g_freezetag_frozen_maxtime * (1 - STAT(REVIVE_PROGRESS, player));
+                               }
+                               // don't clear revive progress, it would allow stacking points
+                               // by entering and exiting the revival zone many times
+                               STAT(REVIVE_PROGRESS, player) = base_progress;
+                       }
+                       else
+                               STAT(REVIVE_PROGRESS, player) = bound(base_progress, STAT(REVIVE_PROGRESS, player) - frametime * clearspeed * (1 - base_progress), 1);
+               }
                else if (!STAT(FROZEN, player) && !player_is_reviving)
                        STAT(REVIVE_PROGRESS, player) = base_progress; // thawing nobody
        }
        else if (STAT(FROZEN, player) == FROZEN_NORMAL) // OK, there is at least one teammate reviving us
        {
-               STAT(REVIVE_PROGRESS, player) = bound(base_progress, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed * (1 - base_progress)), 1);
+               float spd = autocvar_g_freezetag_revive_speed_t2s;
+               if (autocvar_g_freezetag_revive_time_to_score <= 0)
+                       spd = autocvar_g_freezetag_revive_speed * (1 - base_progress);
+               STAT(REVIVE_PROGRESS, player) = bound(base_progress, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, spd), 1);
 
                if(STAT(REVIVE_PROGRESS, player) >= 1)
                {
                        float frozen_time = time - player.freezetag_frozen_time;
                        Unfreeze(player, false);
                        SetResourceExplicit(player, RES_HEALTH, ((warmup_stage) ? warmup_start_health : start_health));
+                       player.spawnshieldtime = time + autocvar_g_freezetag_revive_spawnshield;
                        freezetag_count_alive_players();
 
                        if(n == -1)
@@ -602,7 +628,8 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
                        for(entity it = revivers_first; it; it = it.chain)
                        {
                                GameRules_scoring_add(it, FREEZETAG_REVIVALS, +1);
-                               GameRules_scoring_add(it, SCORE, +1);
+                               if (autocvar_g_freezetag_revive_time_to_score <= 0)
+                                       GameRules_scoring_add(it, SCORE, +1);
                                nades_GiveBonus(it, autocvar_g_nades_bonus_score_low);
                        }
 
@@ -647,14 +674,17 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
 MUTATOR_HOOKFUNCTION(ft, SetStartItems)
 {
        start_items &= ~(IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS);
-       //start_health       = warmup_start_health       = cvar("g_lms_start_health");
-       //start_armorvalue   = warmup_start_armorvalue   = cvar("g_lms_start_armor");
-       start_ammo_shells  = warmup_start_ammo_shells  = cvar("g_lms_start_ammo_shells");
-       start_ammo_nails   = warmup_start_ammo_nails   = cvar("g_lms_start_ammo_nails");
-       start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
-       start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_lms_start_ammo_cells");
-       start_ammo_plasma  = warmup_start_ammo_plasma  = cvar("g_lms_start_ammo_plasma");
-       start_ammo_fuel    = warmup_start_ammo_fuel    = cvar("g_lms_start_ammo_fuel");
+       if(!cvar("g_use_ammunition"))
+               start_items |= IT_UNLIMITED_AMMO;
+
+       start_health       = warmup_start_health       = autocvar_g_ft_start_health;
+       start_armorvalue   = warmup_start_armorvalue   = autocvar_g_ft_start_armor;
+       start_ammo_shells  = warmup_start_ammo_shells  = autocvar_g_ft_start_ammo_shells;
+       start_ammo_nails   = warmup_start_ammo_nails   = autocvar_g_ft_start_ammo_nails;
+       start_ammo_rockets = warmup_start_ammo_rockets = autocvar_g_ft_start_ammo_rockets;
+       start_ammo_cells   = warmup_start_ammo_cells   = autocvar_g_ft_start_ammo_cells;
+       start_ammo_plasma  = warmup_start_ammo_plasma  = autocvar_g_ft_start_ammo_plasma;
+       start_ammo_fuel    = warmup_start_ammo_fuel    = autocvar_g_ft_start_ammo_fuel;
 }
 
 MUTATOR_HOOKFUNCTION(ft, HavocBot_ChooseRole)