Merge branch 'master' into terencehill/ft_autorevive_progress
authorterencehill <piuntn@gmail.com>
Wed, 7 Oct 2020 13:15:05 +0000 (15:15 +0200)
committerterencehill <piuntn@gmail.com>
Wed, 7 Oct 2020 13:15:05 +0000 (15:15 +0200)
gamemodes-server.cfg
qcsrc/client/view.qc
qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qc
qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qh
qcsrc/common/mutators/mutator/waypoints/all.inc
qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc
qcsrc/server/damage.qc
qcsrc/server/player.qc

index 98b6b1a9051c2c13917e46a6748b10263f130b2a..8dd0d5d4897223a09ae2daa1ce6f45231a88cb5f 100644 (file)
@@ -372,6 +372,10 @@ set g_freezetag_revive_extra_size 100 "Distance in qu that you can stand from a
 set g_freezetag_revive_nade 1 "Enable reviving from own nade explosion"
 set g_freezetag_revive_nade_health 40 "Amount of health player has if they revived from their own nade explosion"
 set g_freezetag_round_timelimit 360 "round time limit in seconds"
+set g_freezetag_revive_auto 1 "automatically revive frozen players after some time (g_freezetag_frozen_maxtime)"
+set g_freezetag_revive_auto_progress 1 "start the automatic reviving progress as soon as the player gets frozen"
+set g_freezetag_revive_auto_reducible 1 "reduce auto-revival time when frozen players are hit by enemies; set to -1 to reduce it even when they are hit by teammates"
+set g_freezetag_revive_auto_reducible_forcefactor 0.025 "hit force to time reduction conversion factor"
 set g_freezetag_frozen_maxtime 60 "frozen players will be automatically unfrozen after this time in seconds"
 set g_freezetag_teams_override 0
 set g_freezetag_team_spawns 0 "when 1, players spawn from the team spawnpoints of the map, if any"
index 2b4081aba8a477e379105df27480434754d77082..81d6a634e7f7e7295dbc5ea1eb07af142a98e750 100644 (file)
@@ -952,9 +952,11 @@ void HUD_Draw(entity this)
        else if(STAT(FROZEN))
        {
                vector col = '0.25 0.90 1';
-               if(STAT(REVIVE_PROGRESS))
-                       col += vec3(STAT(REVIVE_PROGRESS), -STAT(REVIVE_PROGRESS), -STAT(REVIVE_PROGRESS));
-               drawfill('0 0 0', vec2(vid_conwidth, vid_conheight), col, autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+               float col_fade = max(0, STAT(REVIVE_PROGRESS) * 2 - 1);
+               float alpha_fade = 0.3 + 0.7 * (1 - max(0, STAT(REVIVE_PROGRESS) * 4 - 3));
+               if(col_fade)
+                       col += vec3(col_fade, -col_fade, -col_fade);
+               drawfill('0 0 0', vec2(vid_conwidth, vid_conheight), col, autocvar_hud_colorflash_alpha * alpha_fade, DRAWFLAG_ADDITIVE);
        }
 
        HUD_Scale_Enable();
index 5378fb346abf9793aa38e76cbc16dc100cf09d8e..ba25fa71617792de6e542092543f13ac5de86383 100644 (file)
@@ -199,7 +199,8 @@ void freezetag_Freeze(entity targ, entity attacker)
        if(STAT(FROZEN, targ))
                return;
 
-       if(autocvar_g_freezetag_frozen_maxtime > 0)
+       targ.freezetag_frozen_time = time;
+       if (autocvar_g_freezetag_revive_auto && autocvar_g_freezetag_frozen_maxtime > 0)
                targ.freezetag_frozen_timeout = time + autocvar_g_freezetag_frozen_maxtime;
 
        Freeze(targ, 0, FROZEN_NORMAL, true);
@@ -458,6 +459,30 @@ MUTATOR_HOOKFUNCTION(ft, Unfreeze)
        targ.freezetag_frozen_timeout = 0;
 }
 
+MUTATOR_HOOKFUNCTION(ft, Damage_Calculate)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       //float frag_deathtype = M_ARGV(3, float);
+       //float frag_damage = M_ARGV(4, float);
+       vector frag_force = M_ARGV(6, vector);
+
+       if (STAT(FROZEN, frag_target) == FROZEN_NORMAL && autocvar_g_freezetag_revive_auto_reducible
+               && autocvar_g_freezetag_frozen_maxtime > 0 && autocvar_g_freezetag_revive_auto)
+       {
+               float t = 0;
+               if ((autocvar_g_freezetag_revive_auto_reducible < 0 || DIFF_TEAM(frag_attacker, frag_target))
+                       && 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;
+                       frag_target.freezetag_frozen_timeout -= t;
+                       if (frag_target.freezetag_frozen_timeout < time)
+                               frag_target.freezetag_frozen_timeout = time;
+               }
+       }
+}
+
 #ifdef IS_REVIVING
        #undef IS_REVIVING
 #endif
@@ -505,30 +530,36 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
        if (!n && player.freezetag_frozen_timeout > 0 && time >= player.freezetag_frozen_timeout)
                n = -1;
 
+       float base_progress = 0;
+       if  (STAT(FROZEN, player) == FROZEN_NORMAL && autocvar_g_freezetag_revive_auto
+               && autocvar_g_freezetag_frozen_maxtime > 0 && autocvar_g_freezetag_revive_auto_progress)
+       {
+               // NOTE if auto-revival is in progress, manual revive speed is reduced so that it always takes the same amount of time
+               base_progress = bound(0, (1 - (player.freezetag_frozen_timeout - time) / autocvar_g_freezetag_frozen_maxtime), 1);
+       }
+
        if (!n) // no teammate nearby
        {
                if (STAT(FROZEN, player) == FROZEN_NORMAL)
-               {
-                       STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) - frametime * autocvar_g_freezetag_revive_clearspeed, 1);
-                       SetResourceExplicit(player, RES_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health)));
-               }
+                       STAT(REVIVE_PROGRESS, player) = bound(base_progress, STAT(REVIVE_PROGRESS, player) - frametime * autocvar_g_freezetag_revive_clearspeed * (1 - base_progress), 1);
                else if (!STAT(FROZEN, player))
-                       STAT(REVIVE_PROGRESS, player) = 0; // thawing nobody
+                       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(0, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
-               SetResourceExplicit(player, RES_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health)));
+               STAT(REVIVE_PROGRESS, player) = bound(base_progress, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed * (1 - base_progress)), 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));
                        freezetag_count_alive_players();
 
                        if(n == -1)
                        {
-                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_AUTO_REVIVED, autocvar_g_freezetag_frozen_maxtime);
-                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_AUTO_REVIVED, player.netname, autocvar_g_freezetag_frozen_maxtime);
+                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_AUTO_REVIVED, frozen_time);
+                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_AUTO_REVIVED, player.netname, frozen_time);
                                return true;
                        }
 
@@ -550,6 +581,24 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
                        STAT(REVIVE_PROGRESS, it) = STAT(REVIVE_PROGRESS, player);
        }
 
+       if (STAT(FROZEN, player) == FROZEN_NORMAL)
+       {
+               entity player_wp = player.waypointsprite_attached;
+               if (n > 0 || (n == 0 && STAT(REVIVE_PROGRESS, player) > 0.95))
+               {
+                       WaypointSprite_UpdateSprites(player_wp, WP_Reviving, WP_Null, WP_Null);
+                       WaypointSprite_UpdateTeamRadar(player_wp, RADARICON_WAYPOINT, WP_REVIVING_COLOR);
+               }
+               else
+               {
+                       WaypointSprite_UpdateSprites(player_wp, WP_Frozen, WP_Null, WP_Null);
+                       WaypointSprite_UpdateTeamRadar(player_wp, RADARICON_WAYPOINT, WP_FROZEN_COLOR);
+               }
+
+               WaypointSprite_UpdateMaxHealth(player_wp, 1);
+               WaypointSprite_UpdateHealth(player_wp, STAT(REVIVE_PROGRESS, player));
+       }
+
        return true;
 }
 
index b77318ca2e808d8929caa9996e184e293b3b6be5..43ceede6ee8d384c2d16d897ffabf2ab5f4e7068 100644 (file)
@@ -33,6 +33,10 @@ const float ICE_MAX_ALPHA = 1;
 const float ICE_MIN_ALPHA = 0.1;
 float freezetag_teams;
 
+bool autocvar_g_freezetag_revive_auto = 1;
+int autocvar_g_freezetag_revive_auto_progress = 1;
+int autocvar_g_freezetag_revive_auto_reducible;
+float autocvar_g_freezetag_revive_auto_reducible_forcefactor;
 float autocvar_g_freezetag_revive_extra_size;
 float autocvar_g_freezetag_revive_speed;
 bool autocvar_g_freezetag_revive_nade;
index c8c4db546a71267d4bb86f7e71e0239ba1c7f629..daa5af4d51dff6d099a53f1cc13d299c94e899df 100644 (file)
@@ -5,7 +5,10 @@ REGISTER_WAYPOINT(Helpme, _("Help me!"), "", '1 0.5 0', 1);
 REGISTER_WAYPOINT(Here, _("Here"), "", '0 1 0', 1);
 REGISTER_WAYPOINT(Danger, _("DANGER"), "", '1 0.5 0', 1);
 
-REGISTER_WAYPOINT(Frozen, _("Frozen!"), "", '0.25 0.90 1', 1);
+const vector WP_FROZEN_COLOR = '0.25 0.9 1';
+const vector WP_REVIVING_COLOR = '1 0.5 0';
+REGISTER_WAYPOINT(Frozen, _("Frozen!"), "", WP_FROZEN_COLOR, 1);
+REGISTER_WAYPOINT(Reviving, _("Reviving"), "", WP_REVIVING_COLOR, 1);
 
 REGISTER_WAYPOINT(Item, _("Item"), "", '1 0 1', 1);
 
index bb6a68863793cb707c6d4e790bbace6a13ae6f89..d3a9806e0f05a808f8addb5384fe08b4e4ec7528 100644 (file)
@@ -881,9 +881,13 @@ void WaypointSprite_UpdateTeamRadar(entity e, entity icon, vector col)
 {
     // no check, as this is never called without doing an actual change (usually only once)
     int i = icon.m_id;
-    e.cnt = (e.cnt & BIT(7)) | (i & BITS(7));
-    e.colormod = col;
-    e.SendFlags |= 32;
+    int new_cnt = (e.cnt & BIT(7)) | (i & BITS(7));
+    if (new_cnt != e.cnt || col != e.colormod)
+    {
+       e.cnt = new_cnt;
+       e.colormod = col;
+       e.SendFlags |= 32;
+    }
 }
 
 void WaypointSprite_Ping(entity e)
index f0655a9f895d2b746281632a6cfeb1b6a03a8e43..b983cdb8aa2e11c26e002a4438a487983c3ef99c 100644 (file)
@@ -629,7 +629,7 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
                                damage = 0;
                                force = '0 0 0';
                        }
-                       else if(SAME_TEAM(attacker, targ))
+                       else if(!STAT(FROZEN, targ) && SAME_TEAM(attacker, targ))
                        {
                                if(autocvar_teamplay_mode == 1)
                                        damage = 0;
@@ -805,7 +805,7 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
 
                        if(IS_PLAYER(victim) || (IS_TURRET(victim) && victim.active == ACTIVE_ACTIVE) || IS_MONSTER(victim) || MUTATOR_CALLHOOK(PlayHitsound, victim, attacker))
                        {
-                               if(DIFF_TEAM(victim, attacker) && !STAT(FROZEN, victim))
+                               if (DIFF_TEAM(victim, attacker))
                                {
                                        if(damage > 0)
                                        {
@@ -828,11 +828,9 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
                                                }
                                        }
                                }
-                               else if(IS_PLAYER(attacker))
+                               else if (IS_PLAYER(attacker) && !STAT(FROZEN, victim)) // same team
                                {
-                                       // if enemy gets frozen in this frame and receives other damage don't
-                                       // play the typehitsound e.g. when hit by multiple bullets of the shotgun
-                                       if (deathtype != DEATH_FIRE.m_id && (!STAT(FROZEN, victim) || time > victim.freeze_time))
+                                       if (deathtype != DEATH_FIRE.m_id)
                                        {
                                                attacker.typehitsound += 1;
                                        }
index a632aab01c7625452f5ff887bd21fb578cf43f43..1be6b62a3f2b8903775047ab2af91d2fdb758d2e 100644 (file)
@@ -247,7 +247,12 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                        }
                }
 
-               if (time < this.spawnshieldtime && autocvar_g_spawnshield_blockdamage < 1)
+               if (STAT(FROZEN, this))
+               {
+                       if (!ITEM_DAMAGE_NEEDKILL(deathtype))
+                               damage = 0;
+               }
+               else if (time < this.spawnshieldtime && autocvar_g_spawnshield_blockdamage < 1)
                        damage *= 1 - max(0, autocvar_g_spawnshield_blockdamage);
 
                if(deathtype & HITTYPE_SOUND) // sound based attacks cause bleeding from the ears
@@ -342,7 +347,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                        if(take)
                                this.pauseregen_finished = max(this.pauseregen_finished, time + autocvar_g_balance_pause_health_regen);
 
-                       if (time > this.pain_finished)          //Don't switch pain sequences like crazy
+                       if (time > this.pain_finished && !STAT(FROZEN, this)) // Don't switch pain sequences like crazy
                        {
                                this.pain_finished = time + 0.5;        //Supajoe
 
@@ -388,8 +393,8 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                        }
 
                        float realdmg = damage - excess;
-                       if (this != attacker && realdmg)
-                       if (!(round_handler_IsActive() && !round_handler_IsRoundStarted()) && time >= game_starttime)
+                       if (this != attacker && realdmg && !STAT(FROZEN, this)
+                               && (!(round_handler_IsActive() && !round_handler_IsRoundStarted()) && time >= game_starttime))
                        {
                                if (IS_PLAYER(attacker) && DIFF_TEAM(attacker, this)) {
                                        GameRules_scoring_add(attacker, DMG, realdmg);
@@ -416,7 +421,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
        if(vbot || IS_REAL_CLIENT(this))
        if(abot || IS_REAL_CLIENT(attacker))
        if(attacker && this != attacker)
-       if(DIFF_TEAM(this, attacker))
+       if (DIFF_TEAM(this, attacker) && (!STAT(FROZEN, this) || this.freeze_time > time))
        {
                if(DEATH_ISSPECIAL(deathtype))
                        awep = attacker.(weaponentity).m_weapon;
@@ -425,8 +430,8 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                valid_damage_for_weaponstats = true;
        }
 
-       dh = dh - max(GetResource(this, RES_HEALTH), 0);
-       da = da - max(GetResource(this, RES_ARMOR), 0);
+       dh -= max(GetResource(this, RES_HEALTH), 0); // health difference
+       da -= max(GetResource(this, RES_ARMOR), 0); // armor difference
        if(valid_damage_for_weaponstats)
        {
                WeaponStats_LogDamage(awep.m_id, abot, this.(weaponentity).m_weapon.m_id, vbot, dh + da);