alias sv_hook_gamestart_ft
alias sv_hook_gamestart_inv
alias sv_hook_gamestart_duel
- alias sv_hook_gamerestart
+ // there is currently no hook for when the match is restarted
+ // see sv_hook_readyrestart for previous uses of this hook
+ //alias sv_hook_gamerestart
alias sv_hook_gameend
// ===========
// this means that timelimit can be overidden globally and fraglimit can be overidden for each game mode: DM/TDM, Domination, CTF, and Runematch.
set leadlimit 0
- set leadlimit_and_fraglimit 0 "if set, leadlimit is ANDed with fraglimit (otherwise ORed)"
+ set leadlimit_and_fraglimit 0 "both leadlimit AND fraglimit must be reached"
set timelimit_override -1 "Time limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
set fraglimit_override -1 "Frag limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
set leadlimit_override -1 "Lead limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
set g_ctf_flag_return_damage 0 "allow the flag to be damaged, reducing time needed to automatically return to base"
set g_ctf_flag_return_damage_delay 0 "how much time the flag takes to automatically return to base if it falls into lava/slime/trigger hurt"
set g_ctf_flag_return_when_unreachable 1 "automatically return the flag if it falls into lava/slime/trigger hurt"
+ set g_ctf_flag_waypoint 1 "show a waypoint at the flag for easy discovery and directions"
+ set g_ctf_flag_waypoint_maxdistance 0 "maximum distance from a flag from which their waypoint is shown, a value of 0 means no limit"
set g_ctf_flagcarrier_auto_helpme_damage 100 "automatically place a helpme notification on flag carrier waypointsprite if they get hit and their health dips below this value"
set g_ctf_flagcarrier_auto_helpme_time 2 "antispam time for the helpme notification"
set g_ctf_flagcarrier_selfdamagefactor 1
set g_ctf_flag_neutral_skin 4
set g_ctf_flag_glowtrails 1
set g_ctf_fullbrightflags 0
- set g_ctf_dynamiclights 0
+ set g_ctf_dynamiclights 0 "flags (not flag carriers) cast light of their team's colour"
set g_ctf_ignore_frags 0 "1: regular frags give no points"
exec ctfscoring-samual.cfg
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; if cvar value is negative reduce time 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"
{
Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
- TeamScore_AddToTeam(winner_team, ST_SCORE, +1);
+ TeamScore_AddToTeam(winner_team, ST_FT_ROUNDS, +1);
}
else if(winner_team == -1)
{
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);
return true;
}
+ 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)
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
if(!round_handler_IsRoundStarted())
return true;
- int n;
entity player = M_ARGV(0, entity);
//if (STAT(FROZEN, player) == FROZEN_NORMAL)
//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);
+ if (!(frametime && IS_PLAYER(player)))
+ return true;
+
entity reviving_players_last = NULL;
entity reviving_players_first = NULL;
- if(player.freezetag_frozen_timeout > 0 && time >= player.freezetag_frozen_timeout)
- n = -1;
- else
- {
- 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;
- });
+ 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 = NULL;
- }
+ 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;
+ 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);
+ STAT(REVIVE_PROGRESS, player) = bound(base_progress, STAT(REVIVE_PROGRESS, player) - frametime * autocvar_g_freezetag_revive_clearspeed * (1 - base_progress), 1);
SetResourceExplicit(player, RES_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health)));
}
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);
+ STAT(REVIVE_PROGRESS, player) = bound(base_progress, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed * (1 - base_progress)), 1);
SetResourceExplicit(player, RES_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health)));
if(STAT(REVIVE_PROGRESS, player) >= 1)
{
+ float frozen_time = time - player.freezetag_frozen_time;
Unfreeze(player, false);
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;
}
return false;
}
+ MUTATOR_HOOKFUNCTION(ft, Scores_CountFragsRemaining)
+ {
+ // announce remaining frags
+ return true;
+ }
+
void freezetag_Initialize()
{
freezetag_teams = autocvar_g_freezetag_teams_override;
freezetag_teams = BITS(bound(2, freezetag_teams, 4));
GameRules_scoring(freezetag_teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {
+ field_team(ST_FT_ROUNDS, "rounds", SFL_SORT_PRIO_PRIMARY);
field(SP_FREEZETAG_REVIVALS, "revivals", 0);
});
bool autocvar_g_freezetag_team_spawns;
string autocvar_g_freezetag_weaponarena = "most_available";
+ const int ST_FT_ROUNDS = 1;
+
void freezetag_Initialize();
REGISTER_MUTATOR(ft, false)
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;
if(w != 0 || slot == 0)
s = strcat(s, ftos(w));
}
- if(time < player.strength_finished)
+ if(time < STAT(STRENGTH_FINISHED, player))
s = strcat(s, "S");
- if(time < player.invincible_finished)
+ if(time < STAT(INVINCIBLE_FINISHED, player))
s = strcat(s, "I");
if(PHYS_INPUT_BUTTON_CHAT(player))
s = strcat(s, "T");
return;
}
- entity deathent = Deathtypes_from(deathtype - DT_FIRST);
+ entity deathent = REGISTRY_GET(Deathtypes, deathtype - DT_FIRST);
if (!deathent)
{
backtrace("Obituary_SpecialDeath: Could not find deathtype entity!\n");
else
{
LOG_TRACEF(
- "Obituary_WeaponDeath(): ^1Deathtype ^7(%d)^1 has no notification for weapon %d!\n",
+ "Obituary_WeaponDeath(): ^1Deathtype ^7(%d)^1 has no notification for weapon %s!\n",
deathtype,
- death_weapon
+ death_weapon.netname
);
}
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;
}
}
- if(deathtype != DEATH_HURTTRIGGER.m_id && deathtype != DEATH_TEAMCHANGE.m_id && deathtype != DEATH_AUTOTEAMCHANGE.m_id && STAT(FROZEN, targ))
+ if(STAT(FROZEN, targ) && !ITEM_DAMAGE_NEEDKILL(deathtype)
+ && deathtype != DEATH_TEAMCHANGE.m_id && deathtype != DEATH_AUTOTEAMCHANGE.m_id)
{
if(autocvar_g_frozen_revive_falldamage > 0 && deathtype == DEATH_FALL.m_id && damage >= autocvar_g_frozen_revive_falldamage)
{
force *= autocvar_g_frozen_force;
}
- if(IS_PLAYER(targ) && STAT(FROZEN, targ) && deathtype == DEATH_HURTTRIGGER.m_id && !autocvar_g_frozen_damage_trigger)
+ if(IS_PLAYER(targ) && STAT(FROZEN, targ)
+ && ITEM_DAMAGE_NEEDKILL(deathtype) && !autocvar_g_frozen_damage_trigger)
{
Send_Effect(EFFECT_TELEPORT, targ.origin, '0 0 0', 1);
- entity spot = SelectSpawnPoint (targ, false);
-
+ entity spot = SelectSpawnPoint(targ, false);
if(spot)
{
damage = 0;
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)
{
}
}
}
- 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;
}
if(attacker == this)
{
- // don't reset pushltime for this damage as it may be an attempt to
+ // don't reset pushltime for self damage as it may be an attempt to
// escape a lava pit or similar
//this.pushltime = 0;
this.istypefrag = 0;
if (take > 100)
Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, this, attacker);
- if (time >= this.spawnshieldtime || autocvar_g_spawnshield_blockdamage < 1)
+ if ((time >= this.spawnshieldtime || autocvar_g_spawnshield_blockdamage < 1)
+ && !STAT(FROZEN, this))
{
if (!(this.flags & FL_GODMODE))
{
float realdmg = damage - excess;
if (this != attacker && realdmg)
+ if (!(round_handler_IsActive() && !round_handler_IsRoundStarted()) && time >= game_starttime)
{
if (IS_PLAYER(attacker) && DIFF_TEAM(attacker, this)) {
GameRules_scoring_add(attacker, DMG, realdmg);
bool valid_damage_for_weaponstats = false;
Weapon awep = WEP_Null;
+ if (!(round_handler_IsActive() && !round_handler_IsRoundStarted()) && time >= game_starttime)
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;
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);