]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into terencehill/ft_autorevive_progress
authorMario <mario.mario@y7mail.com>
Fri, 6 Nov 2020 15:00:06 +0000 (01:00 +1000)
committerMario <mario.mario@y7mail.com>
Fri, 6 Nov 2020 15:00:06 +0000 (01:00 +1000)
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..c15baaf9d101150e0fba283fe39422860894168e 100644 (file)
@@ -371,7 +371,12 @@ set g_freezetag_revive_clearspeed 1.6 "Speed at which reviving progress gets los
 set g_freezetag_revive_extra_size 100 "Distance in qu that you can stand from a frozen teammate to keep reviving him"
 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_revive_time_to_score 1.5 "every this amount of seconds give players reviving a frozen teammate 1 point"
 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 e03dca633c28b54a030d1f65939437858daa0332..c3a93cd052dac5aec44f354521596e826a33a9df 100644 (file)
@@ -944,9 +944,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..ea00927abd908ae3856092f51b8d81d4ab80301b 100644 (file)
@@ -114,6 +114,7 @@ bool freezetag_CheckWinner()
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
                FOREACH_CLIENT(IS_PLAYER(it), {
                        it.freezetag_frozen_timeout = 0;
+                       it.freezetag_revive_time = 0;
                        nades_Clear(it);
                });
                game_stopped = true;
@@ -141,6 +142,7 @@ bool freezetag_CheckWinner()
 
        FOREACH_CLIENT(IS_PLAYER(it), {
                it.freezetag_frozen_timeout = 0;
+               it.freezetag_revive_time = 0;
                nades_Clear(it);
        });
 
@@ -179,7 +181,7 @@ void freezetag_Add_Score(entity targ, entity attacker)
 {
        if(attacker == targ)
        {
-               // you froze your own dumb targ
+               // you froze your own dumb self
                // counted as "suicide" already
                GameRules_scoring_add(targ, SCORE, -1);
        }
@@ -199,7 +201,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);
@@ -437,6 +440,7 @@ MUTATOR_HOOKFUNCTION(ft, reset_map_players)
 {
        FOREACH_CLIENT(IS_PLAYER(it), {
                CS(it).killcount = 0;
+               it.freezetag_revive_time = 0;
                it.freezetag_frozen_timeout = -1;
                PutClientInServer(it);
                it.freezetag_frozen_timeout = 0;
@@ -458,6 +462,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
@@ -490,6 +518,15 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
        int n = 0;
        vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
        FOREACH_CLIENT(IS_PLAYER(it) && IS_REVIVING(player, it, revive_extra_size), {
+               if (autocvar_g_freezetag_revive_time_to_score > 0 && STAT(FROZEN, player) == FROZEN_NORMAL)
+               {
+                       it.freezetag_revive_time += frametime / autocvar_g_freezetag_revive_time_to_score;
+                       while (it.freezetag_revive_time > 1)
+                       {
+                               GameRules_scoring_add(it, SCORE, +1);
+                               it.freezetag_revive_time -= 1;
+                       }
+               }
                if (reviving_players_last)
                        reviving_players_last.chain = it;
                reviving_players_last = it;
@@ -505,30 +542,39 @@ 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
        {
+               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(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 * 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 +596,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..4c88b20de448ebafc0d8aa6195e4da21e0404c2a 100644 (file)
@@ -27,13 +27,19 @@ REGISTER_MUTATOR(ft, false)
        return 0;
 }
 
+.float freezetag_revive_time;
 .float freezetag_frozen_time;
 .float freezetag_frozen_timeout;
 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;
+float autocvar_g_freezetag_revive_time_to_score = 1.5;
 bool autocvar_g_freezetag_revive_nade;
 float autocvar_g_freezetag_revive_nade_health;
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 942f7e8de3e498d0d533c8433f2217aeabbe9a45..8b77c8b14af755f290c0e4ae83e01984a938ad80 100644 (file)
@@ -630,7 +630,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;
@@ -806,7 +806,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)
                                        {
@@ -829,11 +829,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 fa0818283aa55273a42b60e7bbd215e75d856b99..120b738e27f038412861b3b49769e9c6a3cffbcc 100644 (file)
@@ -244,7 +244,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
@@ -339,7 +344,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
 
@@ -385,8 +390,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);
@@ -413,7 +418,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;
@@ -422,8 +427,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);