#include "sv_freezetag.qh"
+#include <server/elimination.qh>
#include <server/resources.qh>
float autocvar_g_freezetag_frozen_maxtime;
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);
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
entity reviving_players_last = NULL;
entity reviving_players_first = NULL;
- int n;
- if(player.freezetag_frozen_timeout > 0 && time >= player.freezetag_frozen_timeout)
+ 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 (reviving_players_last)
+ reviving_players_last.chain = it;
+ reviving_players_last = it;
+ if (!reviving_players_first)
+ reviving_players_first = it;
+ ++n;
+ });
+ if (reviving_players_last)
+ reviving_players_last.chain = NULL;
+
+ // allow normal revival during automatic revival
+ // (not allowing it IS_REVIVING should check freezetag_frozen_timeout too)
+ if (!n && player.freezetag_frozen_timeout > 0 && time >= player.freezetag_frozen_timeout)
n = -1;
- else
+
+ 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)
{
- 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 (reviving_players_last)
- reviving_players_last.chain = it;
- reviving_players_last = it;
- if (!reviving_players_first)
- reviving_players_first = it;
- ++n;
- });
- if (reviving_players_last)
- reviving_players_last.chain = NULL;
+ // 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;
}
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;
}