set g_lms 0 "Last Man Standing: everyone starts with a certain amount of lives, and the survivor wins"
set g_lms_lives_override -1
set g_lms_extra_lives 0
- set g_lms_regenerate 0
+ set g_lms_regenerate 0 "health and/or armor regeneration, according to g_balance_health_regen and g_balance_armor_regen"
+ set g_lms_rot 0 "health and/or armor rotting, according to g_balance_health_rot and g_balance_armor_rot"
set g_lms_last_join 3 "if g_lms_join_anytime is 0, new players can only join if the worst active player has (fraglimit - g_lms_last_join) or more lives; in other words, new players can no longer join once the worst player loses more than g_lms_last_join lives"
set g_lms_join_anytime 1 "1: new players can join, but get same amount of lives as the worst player; 0: new players can only join if the worst active player has (fraglimit - g_lms_last_join) or more lives"
+ set g_lms_items 0 "enables items to spawn, weaponarena still disables weapons and ammo (to force all items to spawn, use g_pickup_items 1 instead)"
set g_lms_weaponarena "most_available" "starting weapons - takes the same options as g_weaponarena"
+set g_lms_leader_lives_diff 2 "players leading by at least this number of lives are considered leaders and are more visible"
+set g_lms_leader_minpercent 0.5 "leading players are not considered leaders only if they are more than this percentage of total players"
+set g_lms_leader_wp_time 5 "show waypoints for leaders only for this amount of time"
+set g_lms_leader_wp_interval 25 "periodically show again waypoints for leaders after this amount of time"
+set g_lms_leader_wp_interval_jitter 10 "jitter waypoint interval by this amount of time"
+set g_lms_dynamic_respawn_delay 1 "increase player respawn delay based on the number of lives less than the leader (NOTE: delay doesn't increase when only 2 players are left alive)"
+set g_lms_dynamic_respawn_delay_base 2 "base player respawn delay"
+set g_lms_dynamic_respawn_delay_increase 3 "increase base player respawn delay by this amount of time for each life less than the leader"
+set g_lms_dynamic_respawn_delay_max 20 "max player respawn delay"
+set g_lms_dynamic_vampire 1 "attackers receive a fraction of health removed from enemies based on the number of lives less than the enemy"
+set g_lms_dynamic_vampire_factor_base 0.1 "base vampire factor"
+set g_lms_dynamic_vampire_factor_increase 0.1 "increase vampire factor by this fraction for each life less than the enemy"
+set g_lms_dynamic_vampire_factor_max 0.5 "max vampire factor"
+set g_lms_dynamic_vampire_min_lives_diff 2 "number of lives the attacker must have less than the enemy to receive the base fraction of health"
+ set g_lms_forfeit_min_match_time 30 "end the match early if at least this many seconds have elapsed and less than 2 players are playing due to forfeits"
// =========
seta notification_CENTER_KEYHUNT_SCAN "1" "0 = off, 1 = centerprint"
seta notification_CENTER_KEYHUNT_START "1" "0 = off, 1 = centerprint"
seta notification_CENTER_LMS_NOLIVES "1" "0 = off, 1 = centerprint"
+ seta notification_CENTER_LMS_SPECWARN "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_LMS_VISIBLE_LEADER "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_LMS_VISIBLE_OTHER "1" "0 = off, 1 = centerprint"
seta notification_CENTER_MISSING_PLAYERS "1" "0 = off, 1 = centerprint"
seta notification_CENTER_MISSING_TEAMS "1" "0 = off, 1 = centerprint"
seta notification_CENTER_MOTD "1" "0 = off, 1 = centerprint"
seta notification_show_sprees_info_newline "1" "Show attacker spree information for MSG_INFO messages on a separate line than the death notification itself"
seta notification_show_sprees_info_specialonly "1" "Don't show attacker spree information in MSG_INFO messages if it isn't an achievement"
- // Notification counts (total = 841): MSG_ANNCE = 80, MSG_INFO = 334, MSG_CENTER = 243, MSG_MULTI = 156, MSG_CHOICE = 28
-// Notification counts (total = 841): MSG_ANNCE = 80, MSG_INFO = 335, MSG_CENTER = 241, MSG_MULTI = 157, MSG_CHOICE = 28
++// Notification counts (total = 843): MSG_ANNCE = 80, MSG_INFO = 335, MSG_CENTER = 243, MSG_MULTI = 157, MSG_CHOICE = 28
#include <server/items/items.qh>
int autocvar_g_lms_extra_lives;
+ float autocvar_g_lms_forfeit_min_match_time;
bool autocvar_g_lms_join_anytime;
int autocvar_g_lms_last_join;
+ bool autocvar_g_lms_items;
bool autocvar_g_lms_regenerate;
+int autocvar_g_lms_leader_lives_diff = 2;
+float autocvar_g_lms_leader_minpercent = 0.5;
+float autocvar_g_lms_leader_wp_interval = 25;
+float autocvar_g_lms_leader_wp_interval_jitter = 10;
+float autocvar_g_lms_leader_wp_time = 5;
+float autocvar_g_lms_dynamic_respawn_delay = 1;
+float autocvar_g_lms_dynamic_respawn_delay_base = 2;
+float autocvar_g_lms_dynamic_respawn_delay_increase = 3;
+float autocvar_g_lms_dynamic_respawn_delay_max = 20;
+bool autocvar_g_lms_dynamic_vampire = 1;
+float autocvar_g_lms_dynamic_vampire_factor_base = 0.1;
+float autocvar_g_lms_dynamic_vampire_factor_increase = 0.1;
+float autocvar_g_lms_dynamic_vampire_factor_max = 0.5;
+int autocvar_g_lms_dynamic_vampire_min_lives_diff = 2;
+
+.float lms_leader;
+int lms_leaders;
+float lms_visible_leaders_time;
+bool lms_visible_leaders = true; // triggers lms_visible_leaders_time update in the first frame
+bool lms_visible_leaders_prev;
+ bool autocvar_g_lms_rot;
// main functions
int LMS_NewPlayerLives()
player.deadflag = DEAD_RESPAWNING;
}
+MUTATOR_HOOKFUNCTION(lms, SV_StartFrame)
+{
+ float leader_time = autocvar_g_lms_leader_wp_time;
+ float leader_interval = leader_time + autocvar_g_lms_leader_wp_interval;
+ lms_visible_leaders_prev = lms_visible_leaders;
+ lms_visible_leaders = (time > lms_visible_leaders_time && time < lms_visible_leaders_time + leader_time);
+ if (lms_visible_leaders_prev && !lms_visible_leaders)
+ lms_visible_leaders_time = time + leader_interval + random() * autocvar_g_lms_leader_wp_interval_jitter;
+
+ lms_leaders = 0;
+ FOREACH_CLIENT(true, {
+ STAT(OBJECTIVE_STATUS, it) = lms_visible_leaders;
+ if (IS_PLAYER(it) && it.frags != FRAGS_PLAYER_OUT_OF_GAME)
+ {
+ if (it.lms_leader)
+ {
+ if (!it.waypointsprite_attachedforcarrier)
+ {
+ WaypointSprite_AttachCarrier(WP_LmsLeader, it, RADARICON_FLAGCARRIER);
+ it.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = lms_waypointsprite_visible_for_player;
+ WaypointSprite_UpdateRule(it.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
+ vector pl_color = colormapPaletteColor(it.clientcolors & 0x0F, false);
+ WaypointSprite_UpdateTeamRadar(it.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, pl_color);
+ WaypointSprite_Ping(it.waypointsprite_attachedforcarrier);
+ }
+ if (!lms_visible_leaders_prev && lms_visible_leaders && IS_REAL_CLIENT(it))
+ Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_LMS_VISIBLE_LEADER);
+ lms_leaders++;
+ }
+ else // if (!it.lms_leader)
+ {
+ if (IS_PLAYER(it) && it.frags != FRAGS_PLAYER_OUT_OF_GAME)
+ {
+ if (!lms_visible_leaders_prev && lms_visible_leaders && IS_REAL_CLIENT(it))
+ Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_LMS_VISIBLE_OTHER);
+ }
+ if (it.waypointsprite_attachedforcarrier)
+ WaypointSprite_Kill(it.waypointsprite_attachedforcarrier);
+ }
+ }
+ });
+}
+
MUTATOR_HOOKFUNCTION(lms, PlayerRegen)
{
- if(autocvar_g_lms_regenerate)
- return false;
- return true;
+ if(!autocvar_g_lms_regenerate)
+ M_ARGV(2, float) = 0;
+ if(!autocvar_g_lms_rot)
+ M_ARGV(3, float) = 0;
+ return (!autocvar_g_lms_regenerate && !autocvar_g_lms_rot);
}
+MUTATOR_HOOKFUNCTION(lms, PlayerPowerups)
+{
+ entity player = M_ARGV(0, entity);
+ if (player.waypointsprite_attachedforcarrier)
+ player.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
+ else
+ player.effects &= ~(EF_ADDITIVE | EF_FULLBRIGHT);
+}
+
MUTATOR_HOOKFUNCTION(lms, ForbidThrowCurrentWeapon)
{
// forbode!
MULTITEAM_CENTER(KEYHUNT_START, N_ENABLE, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGYou are starting with the ^TC^TT Key"), "", KEY)
MSG_CENTER_NOTIF(LMS_NOLIVES, N_ENABLE, 0, 0, "", CPID_LMS, "0 0", _("^BGYou have no lives left, you must wait until the next match"), "")
+ MSG_CENTER_NOTIF(LMS_SPECWARN, N_ENABLE, 0, 0, "", CPID_LMS, "0 0", _("^F4WARNING:^BG you can't rejoin this match after spectating.\nUse the same command again to spectate anyway."), "")
+ MSG_CENTER_NOTIF(LMS_VISIBLE_LEADER, N_ENABLE, 0, 0, "", CPID_LMS, "0 0", _("^BGEnemies can now see you on radar!"), "")
+ MSG_CENTER_NOTIF(LMS_VISIBLE_OTHER, N_ENABLE, 0, 0, "", CPID_LMS, "0 0", _("^BGLeaders can now be seen by enemies on radar!"), "")
MSG_CENTER_NOTIF(MISSING_TEAMS, N_ENABLE, 0, 1, "missing_teams", CPID_MISSING_TEAMS, "-1 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "")
MSG_CENTER_NOTIF(MISSING_PLAYERS, N_ENABLE, 0, 1, "f1", CPID_MISSING_PLAYERS, "-1 0", _("^BGWaiting for %s player(s) to join..."), "")