alias hud_panel_radar_maximized "cl_cmd hud radar"
// other hud cvars
+seta hud_panel_update_interval 2 "how often (in seconds) common panel cvars are reloaded"
+
seta hud_showbinds 1 "what to show in the HUD to indicate certain keys to press: 0 display commands, 1 bound keys, 2 both"
seta hud_showbinds_limit 2 "maximum number of bound keys to show for a command. 0 for unlimited"
set _hud_showbinds_reload 0 "set it to 1 to reload binds if you changed any. It is reset to 0 automatically"
seta hud_panel_modicons_bg_alpha "" "if set to something else than \"\" = override default panel background alpha"
seta hud_panel_modicons_bg_border "" "if set to something else than \"\" = override default size of border around the background"
seta hud_panel_modicons_bg_padding "" "if set to something else than \"\" = override default padding of contents from border"
+seta hud_panel_modicons_ca_layout "" "2 possible layouts: 0) number of alive players; 1) icons and number of alive players"
seta hud_panel_modicons_dom_layout "" "3 possible layouts: 0) only icons; 1) icons and percentage of average pps (points per second); 2) icons and average pps"
+seta hud_panel_modicons_freezetag_layout "" "2 possible layouts: 0) number of alive players; 1) icons and number of alive players"
seta hud_panel_pressedkeys "" "enable/disable this panel, 1 = show only when spectating other players, 2 = show always"
seta hud_panel_pressedkeys_pos "" "position of this base of the panel"
set g_balance_crylink_reload_time 2
// }}}
// {{{ nex
-set g_balance_nex_primary_damage 90
+set g_balance_nex_primary_damage 80
set g_balance_nex_primary_force 400
set g_balance_nex_primary_refire 1.5
-set g_balance_nex_primary_animtime 0.4
+set g_balance_nex_primary_animtime 0.5
set g_balance_nex_primary_ammo 6
set g_balance_nex_primary_damagefalloff_mindist 0 // 1000 For tZork ;3
set g_balance_nex_primary_damagefalloff_maxdist 0 // 3000
set g_balance_crylink_reload_time 2
// }}}
// {{{ nex
-set g_balance_nex_primary_damage 90
+set g_balance_nex_primary_damage 80
set g_balance_nex_primary_force 400
set g_balance_nex_primary_refire 1.5
-set g_balance_nex_primary_animtime 0.4
+set g_balance_nex_primary_animtime 0.5
set g_balance_nex_primary_ammo 6
set g_balance_nex_primary_damagefalloff_mindist 0 // 1000 For tZork ;3
set g_balance_nex_primary_damagefalloff_maxdist 0 // 3000
seta "userbind9_press" "say_team defending (l:%l^7) (h:%h^7 a:%a^7 w:%w^7); g_waypointsprite_team_here"; seta "userbind9_release" ""; seta "userbind9_description" "team: defending, icon"
seta "userbind10_press" "say_team roaming (l:%l^7) (h:%h^7 a:%a^7 w:%w^7); g_waypointsprite_team_here"; seta "userbind10_release" ""; seta "userbind10_description" "team: roaming, icon"
seta "userbind11_press" "say_team attacking (l:%l^7) (h:%h^7 a:%a^7 w:%w^7); g_waypointsprite_team_here"; seta "userbind11_release" ""; seta "userbind11_description" "team: attacking, icon"
-seta "userbind12_press" "say_team killed flagcarrier (l:%y^7); g_waypointsprite_team_p"; seta "userbind12_release" ""; seta "userbind12_description" "team: killed flag, icon"
+seta "userbind12_press" "say_team killed flagcarrier (l:%y^7); g_waypointsprite_team_here_p"; seta "userbind12_release" ""; seta "userbind12_description" "team: killed flag, icon"
seta "userbind13_press" "say_team dropped flag (l:%d^7); g_waypointsprite_team_here_d"; seta "userbind13_release" ""; seta "userbind13_description" "team: dropped flag, icon"
seta "userbind14_press" "say_team dropped gun %w^7 (l:%l^7); g_waypointsprite_team_here; wait; dropweapon"; seta "userbind14_release" ""; seta "userbind14_description" "team: drop gun, icon"
// TODO change this to "use" once we can
seta menu_slist_showempty 1 "show servers even if they are no empty and have no opponents to play against"
seta menu_slist_modfilter "" // set to either: !modname or modname. modname of = means "same as we are running now".
-// for menu weapon arena
-set menu_weaponarena_with_laser 0 "also enable the Laser in this weapon arena"
+seta menu_weaponarena ""
seta menu_maxplayers 16 "maxplayers value when the menu starts a game"
set g_arena 0 "Arena: many one-on-one rounds are played to find the winner"
set g_arena_maxspawned 2 "maximum number of players to spawn at once (the rest is spectating, waiting for their turn)"
set g_arena_roundbased 1 "if disabled, the next player will spawn as soon as someone dies"
+set g_arena_round_timelimit 180
set g_arena_warmup 5 "time, newly spawned players have to prepare themselves in round based matches"
set g_ca_warmup 10 "how long the players will have time to run around the map before the round starts"
set g_ca_damage2score_multiplier 0.01
set g_ca_round_timelimit 180
+seta g_ca_teams_override 0
+set g_ca_teams 0
+
// ==================
// freezetag
// ===========
set g_freezetag 0 "Freeze Tag: Freeze the opposing team(s) to win, unfreeze teammates by standing next to them"
-seta g_freezetag_warmup 5 "Time players get to run around before the round starts"
+set g_freezetag_warmup 5 "Time players get to run around before the round starts"
seta g_freezetag_point_limit -1 "Freeze Tag point limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
seta g_freezetag_point_leadlimit -1 "Freeze Tag point lead limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
-seta g_freezetag_revive_speed 0.4 "Speed for reviving a frozen teammate"
-seta g_freezetag_revive_clearspeed 1.6 "Speed at which reviving progress gets lost when out of range"
-seta g_freezetag_revive_extra_size 100 "Distance in qu that you can stand from a frozen teammate to keep reviving him"
-seta g_freezetag_frozen_force 0.6 "How much to multiply the force on a frozen player with"
+set g_freezetag_revive_speed 0.4 "Speed for reviving a frozen teammate"
+set g_freezetag_revive_clearspeed 1.6 "Speed at which reviving progress gets lost when out of range"
+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_round_timelimit 180
+set g_freezetag_frozen_force 0.6 "How much to multiply the force on a frozen player with"
+set g_freezetag_frozen_maxtime 60 "frozen players will be automatically unfrozen after this time in seconds"
+seta g_freezetag_teams_override 0
+set g_freezetag_teams 0
// ==========
// ===================
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_campcheck_interval 10
set g_lms_campcheck_damage 100
COLOR_INPUTBOX_F '1 1 1'
MARGIN_INPUTBOX_CHARS 1
+// item: clear button
+// uses "clearbutton" images
+OFFSET_CLEARBUTTON -0.3
+COLOR_CLEARBUTTON_N '1 1 1'
+COLOR_CLEARBUTTON_C '1 1 1'
+COLOR_CLEARBUTTON_F '1 1 1'
+
// item: key grabber
COLOR_KEYGRABBER_TITLES '1 1 1'
ALPHA_KEYGRABBER_TITLES 1
COLOR_INPUTBOX_F '1 1 1'
MARGIN_INPUTBOX_CHARS 1
+// item: clear button
+// uses "clearbutton" images
+OFFSET_CLEARBUTTON -0.5
+COLOR_CLEARBUTTON_N '1 1 1'
+COLOR_CLEARBUTTON_C '1 1 1'
+COLOR_CLEARBUTTON_F '1 1 1'
+
// item: key grabber
COLOR_KEYGRABBER_TITLES '1 1 1'
ALPHA_KEYGRABBER_TITLES 1
COLOR_INPUTBOX_F '1 1 1'
MARGIN_INPUTBOX_CHARS 1
+// item: clear button
+// uses "clearbutton" images
+OFFSET_CLEARBUTTON 0
+COLOR_CLEARBUTTON_N '1 1 1'
+COLOR_CLEARBUTTON_C '1 1 1'
+COLOR_CLEARBUTTON_F '1 1 1'
+
// item: key grabber
COLOR_KEYGRABBER_TITLES '1 1 1'
ALPHA_KEYGRABBER_TITLES 1
seta hud_panel_modicons_bg_alpha ""
seta hud_panel_modicons_bg_border ""
seta hud_panel_modicons_bg_padding "0"
+seta hud_panel_modicons_ca_layout "1"
seta hud_panel_modicons_dom_layout "1"
+seta hud_panel_modicons_freezetag_layout "1"
seta hud_panel_pressedkeys 1
seta hud_panel_pressedkeys_pos "0.450000 0.720000"
seta hud_panel_modicons_bg_alpha ""
seta hud_panel_modicons_bg_border ""
seta hud_panel_modicons_bg_padding ""
+seta hud_panel_modicons_ca_layout "1"
seta hud_panel_modicons_dom_layout "1"
+seta hud_panel_modicons_freezetag_layout "1"
seta hud_panel_pressedkeys 1
seta hud_panel_pressedkeys_pos "0.450000 0.650000"
seta hud_panel_modicons_bg_alpha ""
seta hud_panel_modicons_bg_border ""
seta hud_panel_modicons_bg_padding ""
+seta hud_panel_modicons_ca_layout "1"
seta hud_panel_modicons_dom_layout "1"
+seta hud_panel_modicons_freezetag_layout "1"
seta hud_panel_pressedkeys 1
seta hud_panel_pressedkeys_pos "0.450000 0.690000"
seta hud_panel_modicons_bg_alpha ""
seta hud_panel_modicons_bg_border ""
seta hud_panel_modicons_bg_padding ""
+seta hud_panel_modicons_ca_layout "1"
seta hud_panel_modicons_dom_layout "1"
+seta hud_panel_modicons_freezetag_layout "1"
seta hud_panel_pressedkeys 1
seta hud_panel_pressedkeys_pos "0.410000 0.710000"
seta hud_panel_modicons_bg_alpha ""
seta hud_panel_modicons_bg_border ""
seta hud_panel_modicons_bg_padding ""
+seta hud_panel_modicons_ca_layout "1"
seta hud_panel_modicons_dom_layout "1"
+seta hud_panel_modicons_freezetag_layout "1"
seta hud_panel_pressedkeys 1
seta hud_panel_pressedkeys_pos "0.440000 0.760000"
// ** ** //
// ********************************************** //
-// MSG_INFO notifications (count = 208):
+// MSG_ANNCE notifications (count = 39):
+seta notification_ANNCE_ACHIEVEMENT_AIRSHOT "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_ACHIEVEMENT_AMAZING "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_ACHIEVEMENT_AWESOME "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_ACHIEVEMENT_BOTLIKE "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_ACHIEVEMENT_ELECTROBITCH "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_ACHIEVEMENT_IMPRESSIVE "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_ACHIEVEMENT_YODA "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_BEGIN "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_KILLSTREAK_03 "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_KILLSTREAK_05 "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_KILLSTREAK_10 "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_KILLSTREAK_15 "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_KILLSTREAK_20 "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_KILLSTREAK_25 "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_KILLSTREAK_30 "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_MINSTAGIB_LASTSECOND "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_MINSTAGIB_NARROWLY "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_MINSTAGIB_TERMINATED "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_MULTIFRAG "0" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_NUM_1 "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_NUM_2 "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_NUM_3 "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_NUM_4 "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_NUM_5 "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_NUM_6 "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_NUM_7 "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_NUM_8 "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_NUM_9 "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_NUM_10 "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_PREPARE "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_REMAINING_FRAG_1 "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_REMAINING_FRAG_2 "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_REMAINING_FRAG_3 "1" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_REMAINING_MIN_1 "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_REMAINING_MIN_5 "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_TIMEOUT "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_VOTE_ACCEPT "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_VOTE_CALL "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+seta notification_ANNCE_VOTE_FAIL "2" "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)"
+
+// MSG_INFO notifications (count = 207):
seta notification_INFO_CTF_CAPTURE_RED "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_CTF_CAPTURE_BLUE "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_CTF_CAPTURE_BROKEN_RED "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_JOIN_CONNECT_TEAM_BLUE "2" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_JOIN_CONNECT_TEAM_YELLOW "2" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_JOIN_CONNECT_TEAM_PINK "2" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
-seta notification_INFO_JOIN_PLAY "2" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+seta notification_INFO_JOIN_PLAY "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_KEEPAWAY_DROPPED "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_KEEPAWAY_PICKUP "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_KEYHUNT_CAPTURE_RED "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_QUIT_DISCONNECT "2" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_QUIT_KICK_IDLING "2" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_QUIT_KICK_SPECTATING "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
-seta notification_INFO_QUIT_SPECTATE "2" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+seta notification_INFO_QUIT_SPECTATE "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_RACE_ABANDONED "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_RACE_FAIL_RANKED "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_RACE_FAIL_UNRANKED "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_WEAPON_RIFLE_MURDER "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_WEAPON_RIFLE_MURDER_HAIL "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_WEAPON_RIFLE_MURDER_HAIL_PIERCING "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
-seta notification_INFO_WEAPON_RIFLE_MURDER_HEADSHOT "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_WEAPON_RIFLE_MURDER_PIERCING "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_WEAPON_ROCKETLAUNCHER_MURDER_DIRECT "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_WEAPON_ROCKETLAUNCHER_MURDER_SPLASH "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_CENTER_TIMEOUT_BEGINNING "1" "Notification control cvar: 0 = off, 1 = centerprint"
seta notification_CENTER_TIMEOUT_ENDING "1" "Notification control cvar: 0 = off, 1 = centerprint"
-// MSG_MULTI notifications (count = 118):
+// MSG_MULTI notifications (count = 120):
seta notification_DEATH_MURDER_CHEAT "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_DEATH_MURDER_DROWN "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_DEATH_MURDER_FALL "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_ITEM_WEAPON_NOAMMO "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_ITEM_WEAPON_PRIMORSEC "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_ITEM_WEAPON_UNAVAILABLE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
+seta notification_MULTI_ARENA_BEGIN "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
+seta notification_MULTI_COUNTDOWN_BEGIN "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
+seta notification_MULTI_MINSTA_FINDAMMO "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_WEAPON_ACCORDEON_MURDER "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_WEAPON_ACCORDEON_SUICIDE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_WEAPON_CRYLINK_MURDER "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_WEAPON_RIFLE_MURDER "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_WEAPON_RIFLE_MURDER_HAIL "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_WEAPON_RIFLE_MURDER_HAIL_PIERCING "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
-seta notification_WEAPON_RIFLE_MURDER_HEADSHOT "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_WEAPON_RIFLE_MURDER_PIERCING "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_WEAPON_ROCKETLAUNCHER_MURDER_DIRECT "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_WEAPON_ROCKETLAUNCHER_MURDER_SPLASH "1" "Notification control cvar: 0 = off, 1 = trigger subcalls"
seta notification_ctf_capture_verbose "0" "Show extra information when someone captures a flag"
seta notification_ctf_pickup_enemy_verbose "0" "Show extra information if an enemy picks up a flag"
seta notification_ctf_pickup_team_verbose "0" "Show extra information if a team mate picks up a flag"
+seta notification_debug "0" "Print extra debug information on all notification function calls (Requires -DNOTIFICATIONS_DEBUG flag to be enabled on QCSRC compilation)... 0 = disabled, 1 = dprint, 2 = print"
seta notification_errors_are_fatal "1" "If a notification fails upon initialization, cause a Host_Error to stop the program"
seta notification_frag_verbose "1" "Show extra information when you frag someone (or when you are fragged"
seta notification_item_centerprinttime "1.5" "How long to show item information centerprint messages (like 'You got the Electro' or such)"
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 = 459): MSG_INFO = 208, MSG_CENTER = 133, MSG_MULTI = 118
+// Notification counts (total = 499): MSG_ANNCE = 39, MSG_INFO = 207, MSG_CENTER = 133, MSG_MULTI = 120
-funtyped-nil \
-fno-permissive \
-fvariadic-args \
+ -DNOTIFICATIONS_DEBUG \
$(QCCFLAGS_EXTRA) $(QCCFLAGS_WATERMARK)
else
# this. is. fteqccccccccccccccccccc!
CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
-
+ CALL_ACCUMULATED_FUNCTION(RegisterHUD_Panels);
+
WaypointSprite_Load();
// precaches
DamageInfo_Precache();
Vehicles_Precache();
turrets_precache();
- Announcer_Precache();
Tuba_Precache();
CSQCPlayer_Precache();
hud_skin_path = strzone(strcat("gfx/hud/", autocvar_hud_skin));
hud_configure_prev = -1;
- tab_panel = -1;
draw_currentSkin = strzone(strcat("gfx/menu/", cvar_string("menu_skin")));
}
Net_ReadPingPLReport();
bHandled = true;
break;
- case TE_CSQC_ANNOUNCE:
- Announcer_Play(ReadString());
- bHandled = true;
- break;
case TE_CSQC_WEAPONCOMPLAIN:
Net_WeaponComplain();
bHandled = true;
#define BUTTON_3 4
#define BUTTON_4 8
float cl_notice_run();
+float prev_myteam;
void CSQC_UpdateView(float w, float h)
{
entity e;
#endif
myteam = GetPlayerColor(player_localentnum - 1);
+ if(myteam != prev_myteam)
+ {
+ myteamcolors = colormapPaletteColor(myteam, 1);
+ for(i = 0; i < HUD_PANEL_NUM; ++i)
+ hud_panel[i].update_time = time;
+ prev_myteam = myteam;
+ }
+
ticrate = getstatf(STAT_MOVEVARS_TICRATE) * getstatf(STAT_MOVEVARS_TIMESCALE);
float is_dead = (getstati(STAT_HEALTH) <= 0);
}
}
}
-
- if(autocvar_hud_damage)
+
+ if(autocvar_hud_damage && !getstati(STAT_FROZEN))
{
splash_size_x = max(vid_conwidth, vid_conheight);
splash_size_y = max(vid_conwidth, vid_conheight);
if(getstatf(STAT_REVIVE_PROGRESS))
{
DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_REVIVE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
- drawstring_aspect(eY * 0.64 * vid_conheight, "Revival progress", eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL);
+ drawstring_aspect(eY * 0.64 * vid_conheight, _("Revival progress"), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL);
}
}
-float previous_announcement_time;
-float previous_game_starttime;
-string previous_announcement;
-
-// remaining maptime announcer sounds, true when sound was already played
-float announcer_1min;
-float announcer_5min;
-
void Announcer_Play(string announcement)
{
- if((announcement != previous_announcement) || (time >= (previous_announcement_time + autocvar_cl_announcer_antispam)))
+ /*if((announcement != previous_announcement) || (time >= (previous_announcement_time + autocvar_cl_announcer_antispam)))
{
sound(world, CH_INFO, strcat("announcer/", autocvar_cl_announcer, "/", announcement, ".wav"), VOL_BASEVOICE, ATTN_NONE);
previous_announcement = strzone(announcement);
previous_announcement_time = time;
- }
+ }*/
}
+float announcer_1min;
+float announcer_5min;
void Announcer_Countdown()
{
float starttime = getstatf(STAT_GAMESTARTTIME);
+ float roundstarttime = getstatf(STAT_ROUNDSTARTTIME);
+ if(roundstarttime == -1)
+ {
+ Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_ROUNDSTOP);
+ remove(self);
+ return;
+ }
+ if(roundstarttime >= starttime)
+ starttime = roundstarttime;
+ if(starttime <= time && roundstarttime != starttime) // game start time has passed
+ announcer_5min = announcer_1min = FALSE; // reset maptime announcers now as well
+
float countdown = (starttime - time);
float countdown_rounded = floor(0.5 + countdown);
-
+
if(countdown <= 0) // countdown has finished, starttime is now
{
- if (!spectatee_status)
- Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_BEGIN);
-
- Announcer_Play("begin");
- announcer_5min = announcer_1min = FALSE; // reset maptime announcers now as well
+ Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_BEGIN);
+ Local_Notification(MSG_MULTI, MULTI_COUNTDOWN_BEGIN);
remove(self);
return;
}
else // countdown is still going
{
- if (!spectatee_status)
+ if(roundstarttime == starttime)
+ Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_ROUNDSTART, countdown_rounded);
+ else
Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_GAMESTART, countdown_rounded);
- if(countdown_rounded <= 3 && countdown_rounded >= 1)
- Announcer_Play(ftos(countdown_rounded));
+ switch(countdown_rounded)
+ {
+ case 1: Local_Notification(MSG_ANNCE, ANNCE_NUM_1); break;
+ case 2: Local_Notification(MSG_ANNCE, ANNCE_NUM_2); break;
+ case 3: Local_Notification(MSG_ANNCE, ANNCE_NUM_3); break;
+ }
self.nextthink = (starttime - (countdown - 1));
}
* timelimit, fraglimit and game_starttime! Requires engine changes (remove STAT_TIMELIMIT
* and STAT_FRAGLIMIT to be auto-sent)
*/
+ float previous_game_starttime;
void Announcer_Gamestart()
{
float startTime = getstatf(STAT_GAMESTARTTIME);
-
+ float roundstarttime = getstatf(STAT_ROUNDSTARTTIME);
+ if(roundstarttime > startTime)
+ startTime = roundstarttime;
+
if(previous_game_starttime != startTime)
{
if((time + 5.0) < startTime) // if connecting to server while restart was active don't always play prepareforbattle
- Announcer_Play("prepareforbattle");
-
+ Local_Notification(MSG_ANNCE, ANNCE_PREPARE);
+
if(time < startTime)
{
- entity e;
- e = spawn();
- e.think = Announcer_Countdown;
+ entity e = find(world, classname, "announcer_countdown");
+ if not(e)
+ {
+ e = spawn();
+ e.classname = "announcer_countdown";
+ e.think = Announcer_Countdown;
+ }
e.nextthink = startTime - floor(startTime - time); //synchronize nextthink to startTime
}
}
if not(autocvar_g_warmup_limit == -1 && warmup_stage)
{
announcer_5min = TRUE;
- Announcer_Play("5minutesremain");
+ Local_Notification(MSG_ANNCE, ANNCE_REMAINING_MIN_5);
}
}
}
if not(autocvar_g_warmup_limit == -1 && warmup_stage)
{
announcer_1min = TRUE;
- Announcer_Play("1minuteremains");
+ Local_Notification(MSG_ANNCE, ANNCE_REMAINING_MIN_1);
}
}
}
Announcer_Gamestart();
Announcer_Time();
}
-
-void Announcer_Precache ()
-{
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/1minuteremains.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/5minutesremain.wav"));
-
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/electrobitch.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/airshot.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/03kills.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/05kills.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/10kills.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/15kills.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/20kills.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/25kills.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/30kills.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/botlike.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/yoda.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/amazing.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/awesome.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/impressive.wav"));
-
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/prepareforbattle.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/begin.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/timeoutcalled.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/1fragleft.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/2fragsleft.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/3fragsleft.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/terminated.wav"));
-
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/1.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/2.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/3.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/4.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/5.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/6.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/7.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/8.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/9.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/10.wav"));
-
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/lastsecond.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/narrowly.wav"));
-
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/voteaccept.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/votecall.wav"));
- precache_sound (strcat("announcer/", autocvar_cl_announcer, "/votefail.wav"));
-}
float autocvar_hud_panel_infomessages;
float autocvar_hud_panel_infomessages_flip;
float autocvar_hud_panel_modicons;
+float autocvar_hud_panel_modicons_ca_layout;
float autocvar_hud_panel_modicons_dom_layout;
+float autocvar_hud_panel_modicons_freezetag_layout;
float autocvar_hud_panel_notify;
float autocvar_hud_panel_notify_fadetime;
float autocvar_hud_panel_notify_flip;
float autocvar_hud_panel_score_rankings;
float autocvar_hud_panel_timer;
float autocvar_hud_panel_timer_increment;
+float autocvar_hud_panel_update_interval;
float autocvar_hud_panel_vote;
float autocvar_hud_panel_vote_alreadyvoted_alpha;
string autocvar_hud_panel_vote_bg_alpha;
}
self.csqcmodel_isdead = IS_DEAD_FRAME(self.frame);
}
+void CSQCPlayer_AnimDecide_PostUpdate(float isnew)
+{
+ self.csqcmodel_isdead = !!(self.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2));
+}
float CSQCPlayer_FallbackFrame(float f)
{
if(frameduration(self.modelindex, f) > 0)
if(self.isplayermodel)
{
CSQCPlayer_ForceModel_PostUpdate();
- if(!isplayer)
+ if(isplayer)
+ CSQCPlayer_AnimDecide_PostUpdate(isnew);
+ else
CSQCPlayer_FallbackFrame_PostUpdate(isnew);
}
CSQCModel_Effects_PostUpdate();
return;
}
}
- else
- hud_configure_active_panel = HUD_PANEL_WEAPONS;
// update generic hud functions
- HUD_Panel_UpdateCvars(weapons);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
draw_beginBoldFont();
if(!autocvar_hud_panel_ammo) return;
if(spectatee_status == -1) return;
}
- else
- hud_configure_active_panel = HUD_PANEL_AMMO;
- HUD_Panel_UpdateCvars(ammo);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
draw_beginBoldFont();
}
else
{
- hud_configure_active_panel = HUD_PANEL_POWERUPS;
-
strength_time = 15;
shield_time = 27;
superweapons_time = 13;
}
- HUD_Panel_UpdateCvars(powerups);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
draw_beginBoldFont();
}
else
{
- hud_configure_active_panel = HUD_PANEL_HEALTHARMOR;
-
health = 150;
armor = 75;
fuel = 20;
}
- HUD_Panel_UpdateCvars(healtharmor);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
vector pos, mySize;
pos = panel_pos;
{
if(!autocvar_hud_panel_notify) return;
}
- else
- hud_configure_active_panel = HUD_PANEL_NOTIFY;
- HUD_Panel_UpdateCvars(notify);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
vector pos, mySize;
pos = panel_pos;
{
if(!autocvar_hud_panel_timer) return;
}
- else
- hud_configure_active_panel = HUD_PANEL_TIMER;
- HUD_Panel_UpdateCvars(timer);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
draw_beginBoldFont();
if (autocvar_hud_panel_radar != 2 && !teamplay) return;
}
}
- else
- hud_configure_active_panel = HUD_PANEL_RADAR;
- HUD_Panel_UpdateCvars(radar);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
-
+
float f = 0;
if (hud_panel_radar_maximized && !autocvar__hud_configure)
if(!autocvar_hud_panel_score) return;
if(spectatee_status == -1 && (gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
}
- else
- hud_configure_active_panel = HUD_PANEL_SCORE;
- HUD_Panel_UpdateCvars(score);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
vector pos, mySize;
pos = panel_pos;
if(!(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
if(spectatee_status == -1) return;
}
- else
- hud_configure_active_panel = HUD_PANEL_RACETIMER;
- HUD_Panel_UpdateCvars(racetimer);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
draw_beginBoldFont();
float vote_alpha;
float vote_change; // "time" when vote_active changed
-void HUD_VoteWindow(void)
+void HUD_Vote(void)
{
if(autocvar_cl_allow_uid2name == -1 && (gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || (serverflags & SERVERFLAG_PLAYERSTATS)))
{
}
else
{
- hud_configure_active_panel = HUD_PANEL_VOTE;
-
vote_yescount = 3;
vote_nocount = 2;
vote_needed = 4;
if(!vote_alpha)
return;
- HUD_Panel_UpdateCvars(vote);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
if(uid2name_dialog)
float mod_active; // is there any active mod icon?
-// Clan Arena HUD modicons
-void HUD_Mod_CA(vector pos, vector mySize)
+void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, float layout, float i)
{
- mod_active = 1; // CA should never hide the mod icons panel
- float redalive, bluealive;
- redalive = getstati(STAT_REDALIVE);
- bluealive = getstati(STAT_BLUEALIVE);
+ float stat;
+ string pic;
+ vector color;
+#ifdef GMQCC
+ stat = -1;
+ pic = "";
+ color = '0 0 0';
+#endif
+ switch(i)
+ {
+ case 0:
+ stat = getstati(STAT_REDALIVE);
+ pic = "player_red.tga";
+ color = '1 0 0';
+ break;
+ case 1:
+ stat = getstati(STAT_BLUEALIVE);
+ pic = "player_blue.tga";
+ color = '0 0 1';
+ break;
+ case 2:
+ stat = getstati(STAT_YELLOWALIVE);
+ pic = "player_yellow.tga";
+ color = '1 1 0';
+ break;
+ default:
+ case 3:
+ stat = getstati(STAT_PINKALIVE);
+ pic = "player_pink.tga";
+ color = '1 0 1';
+ break;
+ }
- vector redpos, bluepos;
- if(mySize_x > mySize_y)
+ if(mySize_x/mySize_y > aspect_ratio)
{
- redpos = pos;
- bluepos = pos + eY * 0.5 * mySize_y;
- drawpic_aspect_skin(redpos, "player_red.tga", 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(redpos + eX * 0.5 * mySize_x, ftos(redalive), 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawpic_aspect_skin(bluepos, "player_blue.tga", 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(bluepos + eX * 0.5 * mySize_x, ftos(bluealive), 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ i = aspect_ratio * mySize_y;
+ myPos_x = myPos_x + (mySize_x - i) / 2;
+ mySize_x = i;
}
else
{
- redpos = pos;
- bluepos = pos + eY * 0.5 * mySize_y;
- drawpic_aspect_skin(redpos, "player_red.tga", eX * mySize_x + eY * 0.3 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(redpos + eY * 0.3 * mySize_y, ftos(redalive), eX * mySize_x + eY * 0.2 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawpic_aspect_skin(bluepos, "player_blue.tga", eX * mySize_x + eY * 0.3 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(bluepos + eY * 0.3 * mySize_y, ftos(bluealive), eX * mySize_x + eY * 0.2 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ i = 1/aspect_ratio * mySize_x;
+ myPos_y = myPos_y + (mySize_y - i) / 2;
+ mySize_y = i;
+ }
+
+ if(layout)
+ {
+ drawpic_aspect_skin(myPos, pic, eX * 0.7 * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(myPos + eX * 0.7 * mySize_x, ftos(stat), eX * 0.3 * mySize_x + eY * mySize_y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ else
+ drawstring_aspect(myPos, ftos(stat), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
+// Clan Arena and Freeze Tag HUD modicons
+void HUD_Mod_CA(vector myPos, vector mySize)
+{
+ mod_active = 1; // required in each mod function that always shows something
+ entity tm;
+ float teams_count = 0;
+ for(tm = teams.sort_next; tm; tm = tm.sort_next)
+ if(tm.team != NUM_SPECTATOR)
+ ++teams_count;
+
+ float layout;
+ if(gametype == MAPINFO_TYPE_CA)
+ layout = autocvar_hud_panel_modicons_ca_layout;
+ else //if(gametype == MAPINFO_TYPE_FREEZETAG)
+ layout = autocvar_hud_panel_modicons_freezetag_layout;
+ float rows, columns, aspect_ratio;
+ rows = mySize_y/mySize_x;
+ aspect_ratio = (layout) ? 2 : 1;
+ rows = bound(1, floor((sqrt((4 * aspect_ratio * teams_count + rows) * rows) + rows + 0.5) / 2), teams_count);
+ columns = ceil(teams_count/rows);
+
+ int i;
+ float row = 0, column = 0;
+ vector pos, itemSize;
+ itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
+ for(i=0; i<teams_count; ++i)
+ {
+ pos = myPos + eX * column * itemSize_x + eY * row * itemSize_y;
+
+ DrawCAItem(pos, itemSize, aspect_ratio, layout, i);
+
+ ++row;
+ if(row >= rows)
+ {
+ row = 0;
+ ++column;
+ }
}
}
int i;
float row = 0, column = 0;
+ vector pos, itemSize;
+ itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
for(i=0; i<teams_count; ++i)
{
- vector pos, itemSize;
- pos = myPos + eX * column * mySize_x*(1/columns) + eY * row * mySize_y*(1/rows);
- itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
+ pos = myPos + eX * column * itemSize_x + eY * row * itemSize_y;
DrawDomItem(pos, itemSize, aspect_ratio, layout, i);
if(!autocvar_hud_panel_modicons) return;
if (gametype != MAPINFO_TYPE_CTF && gametype != MAPINFO_TYPE_KEYHUNT && gametype != MAPINFO_TYPE_NEXBALL && gametype != MAPINFO_TYPE_CTS && gametype != MAPINFO_TYPE_RACE && gametype != MAPINFO_TYPE_CA && gametype != MAPINFO_TYPE_FREEZETAG && gametype != MAPINFO_TYPE_KEEPAWAY && gametype != MAPINFO_TYPE_DOMINATION) return;
}
- else
- hud_configure_active_panel = HUD_PANEL_MODICONS;
- HUD_Panel_UpdateCvars(modicons);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
draw_beginBoldFont();
// Draw pressed keys (#11)
//
-void HUD_DrawPressedKeys(void)
+void HUD_PressedKeys(void)
{
if(!autocvar__hud_configure)
{
if(!autocvar_hud_panel_pressedkeys) return;
if(spectatee_status <= 0 && autocvar_hud_panel_pressedkeys < 2) return;
}
- else
- hud_configure_active_panel = HUD_PANEL_PRESSEDKEYS;
-
- HUD_Panel_UpdateCvars(pressedkeys);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
vector pos, mySize;
pos = panel_pos;
if(autocvar__con_chat_maximized)
if(!hud_draw_maximized) return;
}
- else
- hud_configure_active_panel = HUD_PANEL_CHAT;
- HUD_Panel_UpdateCvars(chat);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
if(autocvar__con_chat_maximized && !autocvar__hud_configure) // draw at full screen height if maximized
{
if(!autocvar_hud_panel_engineinfo) return;
}
- else
- hud_configure_active_panel = HUD_PANEL_ENGINEINFO;
- HUD_Panel_UpdateCvars(engineinfo);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
vector pos, mySize;
pos = panel_pos;
{
if(!autocvar_hud_panel_infomessages) return;
}
- else
- hud_configure_active_panel = HUD_PANEL_INFOMESSAGES;
- HUD_Panel_UpdateCvars(infomessages);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
vector pos, mySize;
pos = panel_pos;
if(spectatee_status == -1 && (autocvar_hud_panel_physics == 1 || autocvar_hud_panel_physics == 3)) return;
if(autocvar_hud_panel_physics == 3 && !(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
}
- else
- hud_configure_active_panel = HUD_PANEL_PHYSICS;
- HUD_Panel_UpdateCvars(physics);
+ HUD_Panel_UpdateCvars();
HUD_Panel_ApplyFadeAlpha();
draw_beginBoldFont();
}
else
{
- hud_configure_active_panel = HUD_PANEL_CENTERPRINT;
-
if (!hud_configure_prev)
reset_centerprint_messages();
if (time > hud_configure_cp_generation_time)
}
}
- HUD_Panel_UpdateCvars(centerprint);
+ HUD_Panel_UpdateCvars();
// this panel doesn't fade when showing the scoreboard
if(autocvar__menu_alpha)
HUD_Mod_CTF_Reset();
}
-#define HUD_DrawPanel(id)\
-switch (id) {\
- case (HUD_PANEL_RADAR):\
- HUD_Radar(); break;\
- case (HUD_PANEL_WEAPONS):\
- HUD_Weapons(); break;\
- case (HUD_PANEL_AMMO):\
- HUD_Ammo(); break;\
- case (HUD_PANEL_POWERUPS):\
- HUD_Powerups(); break;\
- case (HUD_PANEL_HEALTHARMOR):\
- HUD_HealthArmor(); break;\
- case (HUD_PANEL_NOTIFY):\
- HUD_Notify(); break;\
- case (HUD_PANEL_TIMER):\
- HUD_Timer(); break;\
- case (HUD_PANEL_SCORE):\
- HUD_Score(); break;\
- case (HUD_PANEL_RACETIMER):\
- HUD_RaceTimer(); break;\
- case (HUD_PANEL_VOTE):\
- HUD_VoteWindow(); break;\
- case (HUD_PANEL_MODICONS):\
- HUD_ModIcons(); break;\
- case (HUD_PANEL_PRESSEDKEYS):\
- HUD_DrawPressedKeys(); break;\
- case (HUD_PANEL_CHAT):\
- HUD_Chat(); break;\
- case (HUD_PANEL_ENGINEINFO):\
- HUD_EngineInfo(); break;\
- case (HUD_PANEL_INFOMESSAGES):\
- HUD_InfoMessages(); break;\
- case (HUD_PANEL_PHYSICS):\
- HUD_Physics(); break;\
- case (HUD_PANEL_CENTERPRINT):\
- HUD_CenterPrint(); break;\
-} ENDS_WITH_CURLY_BRACE
-
void HUD_Main (void)
{
float i;
// they must call HUD_Panel_ApplyFadeAlpha(); only when showing the menu
if(scoreboard_fade_alpha == 1)
{
- HUD_CenterPrint();
+ (panel = HUD_PANEL(CENTERPRINT)).panel_draw();
return;
}
vector color;
float hud_dock_color_team = autocvar_hud_dock_color_team;
if((teamplay) && hud_dock_color_team) {
- color = colormapPaletteColor(myteam, 1) * hud_dock_color_team;
+ if(autocvar__hud_configure && myteam == NUM_SPECTATOR)
+ color = '1 0 0' * hud_dock_color_team;
+ else
+ color = myteamcolors * hud_dock_color_team;
}
else if(autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && hud_dock_color_team) {
color = '1 0 0' * hud_dock_color_team;
hud_draw_maximized = 0;
// draw panels in order specified by panel_order array
for(i = HUD_PANEL_NUM - 1; i >= 0; --i)
- HUD_DrawPanel(panel_order[i]);
+ (panel = hud_panel[panel_order[i]]).panel_draw();
hud_draw_maximized = 1; // panels that may be maximized must check this var
// draw maximized panels on top
if(hud_panel_radar_maximized)
- HUD_Radar();
+ (panel = HUD_PANEL(RADAR)).panel_draw();
if(autocvar__con_chat_maximized)
- HUD_Chat();
+ (panel = HUD_PANEL(CHAT)).panel_draw();
if(autocvar__hud_configure)
{
- if(tab_panel != -1)
+ if(tab_panel)
{
- HUD_Panel_UpdatePosSizeForId(tab_panel)
+ panel = tab_panel;
+ HUD_Panel_UpdatePosSize()
drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .2, DRAWFLAG_NORMAL);
}
- if(highlightedPanel != -1)
+ if(highlightedPanel)
{
- HUD_Panel_UpdatePosSizeForId(highlightedPanel);
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize()
HUD_Panel_HlBorder(panel_bg_border + 1.5 * hlBorderSize, '0 0.5 1', 0.25 * (1 - autocvar__menu_alpha));
}
if(!hud_configure_prev || hud_configure_prev == -1)
{
if(autocvar_hud_cursormode) { setcursormode(1); }
hudShiftState = 0;
+ for(i = HUD_PANEL_NUM - 1; i >= 0; --i)
+ hud_panel[panel_order[i]].update_time = time;
}
}
else if (hud_configure_prev && autocvar_hud_cursormode)
-float panel_order[HUD_PANEL_NUM];
+#define HUD_PANEL_MAX 24
+entity hud_panel[HUD_PANEL_MAX];
+#define HUD_PANEL_FIRST 0
+float HUD_PANEL_NUM;
+float HUD_PANEL_LAST;
+
+float panel_order[HUD_PANEL_MAX];
string hud_panelorder_prev;
float hud_draw_maximized;
vector panel_click_distance; // mouse cursor distance from the top left corner of the panel (saved only upon a click)
vector panel_click_resizeorigin; // coordinates for opposite point when resizing
float resizeCorner; // 1 = topleft, 2 = topright, 3 = bottomleft, 4 = bottomright
-var float highlightedPanel = -1;
+entity highlightedPanel;
float highlightedAction; // 0 = nothing, 1 = move, 2 = resize
const float BORDER_MULTIPLIER = 0.25;
string hud_skin_path;
string hud_skin_prev;
+vector myteamcolors;
+
var vector progressbar_color;
-var float highlightedPanel_backup = -1;
+entity highlightedPanel_backup;
var vector panel_pos_backup;
var vector panel_size_backup;
-var float highlightedPanel_copied = -1; //this is good only to know if there is something copied
var vector panel_size_copied;
-var float hud_configure_active_panel; // this panel has recently referred the UpdateCvars macro
-var string panel_name;
+entity panel;
+.string panel_name;
+.float panel_id;
+.vector current_panel_pos;
+.vector current_panel_size;
+.string current_panel_bg;
+.float current_panel_bg_alpha;
+.float current_panel_bg_border;
+.vector current_panel_bg_color;
+.float current_panel_bg_color_team;
+.float current_panel_bg_padding;
+.float current_panel_fg_alpha;
+.float update_time;
var float panel_enabled;
var vector panel_pos;
var vector panel_size;
var float panel_bg_padding;
var string panel_bg_padding_str;
+.void() panel_draw;
+
float current_player;
+
+#define HUD_PANELS \
+ HUD_PANEL(WEAPONS , HUD_Weapons , weapons) \
+ HUD_PANEL(AMMO , HUD_Ammo , ammo) \
+ HUD_PANEL(POWERUPS , HUD_Powerups , powerups) \
+ HUD_PANEL(HEALTHARMOR , HUD_HealthArmor , healtharmor) \
+ HUD_PANEL(NOTIFY , HUD_Notify , notify) \
+ HUD_PANEL(TIMER , HUD_Timer , timer) \
+ HUD_PANEL(RADAR , HUD_Radar , radar) \
+ HUD_PANEL(SCORE , HUD_Score , score) \
+ HUD_PANEL(RACETIMER , HUD_RaceTimer , racetimer) \
+ HUD_PANEL(VOTE , HUD_Vote , vote) \
+ HUD_PANEL(MODICONS , HUD_ModIcons , modicons) \
+ HUD_PANEL(PRESSEDKEYS , HUD_PressedKeys , pressedkeys) \
+ HUD_PANEL(CHAT , HUD_Chat , chat) \
+ HUD_PANEL(ENGINEINFO , HUD_EngineInfo , engineinfo) \
+ HUD_PANEL(INFOMESSAGES , HUD_InfoMessages , infomessages) \
+ HUD_PANEL(PHYSICS , HUD_Physics , physics) \
+ HUD_PANEL(CENTERPRINT , HUD_CenterPrint , centerprint)
+
+#define HUD_PANEL(NAME,draw_func,name) \
+ float HUD_PANEL_##NAME; \
+ void ##draw_func(void); \
+ void RegisterHUD_Panel_##NAME() \
+ { \
+ HUD_PANEL_LAST = HUD_PANEL_##NAME = HUD_PANEL_NUM; \
+ entity hud_panelent = spawn(); \
+ hud_panel[HUD_PANEL_##NAME] = hud_panelent; \
+ hud_panelent.classname = "hud_panel"; \
+ hud_panelent.panel_name = #name; \
+ hud_panelent.panel_id = HUD_PANEL_##NAME; \
+ hud_panelent.panel_draw = ##draw_func; \
+ ++HUD_PANEL_NUM; \
+ } \
+ ACCUMULATE_FUNCTION(RegisterHUD_Panels, RegisterHUD_Panel_##NAME)
+
+HUD_PANELS
+#undef HUD_PANEL
+
+#define HUD_PANEL(NAME) hud_panel[HUD_PANEL_##NAME]
+
+
// Because calling lots of functions in QC apparently cuts fps in half on many machines:
// ----------------------
// MACRO HELL STARTS HERE
// Get value for panel_bg_color: if "" fetch default, else use panel_bg_color. Convert pants, shirt or teamcolor into a vector.
#define HUD_Panel_GetColor()\
if((teamplay) && panel_bg_color_team) {\
- panel_bg_color = colormapPaletteColor(myteam, 1) * panel_bg_color_team;\
+ if(autocvar__hud_configure && myteam == NUM_SPECTATOR)\
+ panel_bg_color = '1 0 0' * panel_bg_color_team;\
+ else\
+ panel_bg_color = myteamcolors * panel_bg_color_team;\
} else if (autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && panel_bg_color_team) {\
panel_bg_color = '1 0 0' * panel_bg_color_team;\
} else {\
// the check doesn't allow to fade this panel when showing the panel-specific menu dialog
#define HUD_Panel_ApplyFadeAlpha()\
-if(!(menu_enabled == 2 && highlightedPanel == hud_configure_active_panel))\
+if(!(menu_enabled == 2 && panel == highlightedPanel))\
{\
panel_bg_alpha *= hud_fade_alpha;\
panel_fg_alpha *= hud_fade_alpha;\
if(autocvar__hud_configure) {\
if(!panel_enabled)\
panel_bg_alpha = 0.25;\
- else if(menu_enabled == 2 && highlightedPanel == hud_configure_active_panel)\
+ else if(menu_enabled == 2 && panel == highlightedPanel)\
panel_bg_alpha = (1 - autocvar__menu_alpha) * max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha) + autocvar__menu_alpha * panel_bg_alpha;\
else\
panel_bg_alpha = max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha);\
}\
}
-// Update all common cvars of given panel name
-#define HUD_Panel_UpdateCvars(name) \
-panel_enabled = autocvar_hud_panel_##name; \
-panel_pos = stov(cvar_string("hud_panel_" #name "_pos")); \
-panel_size = stov(cvar_string("hud_panel_" #name "_size")); \
-panel_bg_str = cvar_string("hud_panel_" #name "_bg"); \
-panel_bg_color_str = cvar_string("hud_panel_" #name "_bg_color"); \
-panel_bg_color_team_str = cvar_string("hud_panel_" #name "_bg_color_team"); \
-panel_bg_alpha_str = cvar_string("hud_panel_" #name "_bg_alpha"); \
-panel_bg_border_str = cvar_string("hud_panel_" #name "_bg_border"); \
-panel_bg_padding_str = cvar_string("hud_panel_" #name "_bg_padding"); \
-HUD_Panel_GetStringVars()\
-if(menu_enabled == 2 && hud_configure_active_panel == highlightedPanel) {\
- HUD_Panel_GetMenuSize()\
- HUD_Panel_GetMenuPos()\
+// NOTE: in hud_configure mode cvars must be reloaded every frame
+#define HUD_Panel_UpdateCvars() \
+if(panel.update_time <= time) { \
+ if(autocvar__hud_configure) panel_enabled = cvar(strcat("hud_panel_", panel.panel_name)); \
+ panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos"))); \
+ panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size"))); \
+ panel_bg_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg")); \
+ panel_bg_color_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_color")); \
+ panel_bg_color_team_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_color_team")); \
+ panel_bg_alpha_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_alpha")); \
+ panel_bg_border_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_border")); \
+ panel_bg_padding_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_padding")); \
+ HUD_Panel_GetStringVars()\
+ if(menu_enabled == 2 && panel == highlightedPanel) {\
+ HUD_Panel_GetMenuSize()\
+ HUD_Panel_GetMenuPos()\
+ } \
+ panel.current_panel_pos = panel_pos; \
+ panel.current_panel_size = panel_size; \
+ if(panel.current_panel_bg != "") \
+ strunzone(panel.current_panel_bg); \
+ panel.current_panel_bg = strzone(panel_bg); \
+ panel.current_panel_bg_alpha = panel_bg_alpha; \
+ panel.current_panel_bg_border = panel_bg_border; \
+ panel.current_panel_bg_color = panel_bg_color; \
+ panel.current_panel_bg_color_team = panel_bg_color_team; \
+ panel.current_panel_bg_padding = panel_bg_padding; \
+ panel.current_panel_fg_alpha = panel_fg_alpha; \
+ panel.update_time = (autocvar__hud_configure) ? time : time + autocvar_hud_panel_update_interval; \
+} else { \
+ panel_pos = panel.current_panel_pos; \
+ panel_size = panel.current_panel_size; \
+ panel_bg = panel.current_panel_bg; \
+ panel_bg_alpha = panel.current_panel_bg_alpha; \
+ panel_bg_border = panel.current_panel_bg_border; \
+ panel_bg_color = panel.current_panel_bg_color; \
+ panel_bg_color_team = panel.current_panel_bg_color_team; \
+ panel_bg_padding = panel.current_panel_bg_padding; \
+ panel_fg_alpha = panel.current_panel_fg_alpha; \
} ENDS_WITH_CURLY_BRACE
-// FTEQCC I HATE YOU WHY DO YOU MAKE ME DO THIS??? :(
-// max macro length is 1024 characters, I must split it up :(
-
-// Update all common cvars of given panel id
-#define HUD_Panel_UpdateCvarsForId_Part2(id) \
-switch(id) { \
- case HUD_PANEL_INFOMESSAGES: HUD_Panel_UpdateCvars(infomessages) break; \
- case HUD_PANEL_PHYSICS: HUD_Panel_UpdateCvars(physics); break;\
- case HUD_PANEL_CENTERPRINT: HUD_Panel_UpdateCvars(centerprint); break;\
-}
-
-#define HUD_Panel_UpdateCvarsForId(id) \
-switch(id) { \
- case HUD_PANEL_WEAPONS: HUD_Panel_UpdateCvars(weapons) break; \
- case HUD_PANEL_AMMO: HUD_Panel_UpdateCvars(ammo) break; \
- case HUD_PANEL_POWERUPS: HUD_Panel_UpdateCvars(powerups) break; \
- case HUD_PANEL_HEALTHARMOR: HUD_Panel_UpdateCvars(healtharmor) break; \
- case HUD_PANEL_NOTIFY: HUD_Panel_UpdateCvars(notify) break; \
- case HUD_PANEL_TIMER: HUD_Panel_UpdateCvars(timer) break; \
- case HUD_PANEL_RADAR: HUD_Panel_UpdateCvars(radar) break; \
- case HUD_PANEL_SCORE: HUD_Panel_UpdateCvars(score) break; \
- case HUD_PANEL_RACETIMER: HUD_Panel_UpdateCvars(racetimer) break; \
- case HUD_PANEL_VOTE: HUD_Panel_UpdateCvars(vote) break; \
- case HUD_PANEL_MODICONS: HUD_Panel_UpdateCvars(modicons) break; \
- case HUD_PANEL_PRESSEDKEYS: HUD_Panel_UpdateCvars(pressedkeys) break; \
- case HUD_PANEL_CHAT: HUD_Panel_UpdateCvars(chat) break; \
- case HUD_PANEL_ENGINEINFO: HUD_Panel_UpdateCvars(engineinfo) break; \
- default: HUD_Panel_UpdateCvarsForId_Part2(id)\
-}
-
-#define HUD_Panel_UpdatePosSize(name) \
-panel_pos = stov(cvar_string("hud_panel_" #name "_pos")); \
-panel_size = stov(cvar_string("hud_panel_" #name "_size")); \
+#define HUD_Panel_UpdatePosSize() {\
+panel_enabled = cvar(strcat("hud_panel_", panel.panel_name)); \
+panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos"))); \
+panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size"))); \
HUD_Panel_GetScaledVectors()\
-if(menu_enabled == 2 && hud_configure_active_panel == highlightedPanel) {\
+if(menu_enabled == 2 && panel == highlightedPanel) {\
HUD_Panel_GetMenuSize()\
HUD_Panel_GetMenuPos()\
}\
-panel_bg_border_str = cvar_string("hud_panel_" #name "_bg_border"); \
-HUD_Panel_GetBorder()
-
-// Update pos and size of given panel id
-#define HUD_Panel_UpdatePosSizeForId_Part2(id) \
-switch(id) { \
- case HUD_PANEL_INFOMESSAGES: HUD_Panel_UpdatePosSize(infomessages) break;\
- case HUD_PANEL_PHYSICS: HUD_Panel_UpdatePosSize(physics); break;\
- case HUD_PANEL_CENTERPRINT: HUD_Panel_UpdatePosSize(centerprint); break;\
-}
+panel_bg_border_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_border")); \
+HUD_Panel_GetBorder() \
+} ENDS_WITH_CURLY_BRACE
-#define HUD_Panel_UpdatePosSizeForId(id) \
-switch(id) { \
- case HUD_PANEL_WEAPONS: HUD_Panel_UpdatePosSize(weapons) break;\
- case HUD_PANEL_AMMO: HUD_Panel_UpdatePosSize(ammo) break;\
- case HUD_PANEL_POWERUPS: HUD_Panel_UpdatePosSize(powerups) break;\
- case HUD_PANEL_HEALTHARMOR: HUD_Panel_UpdatePosSize(healtharmor) break;\
- case HUD_PANEL_NOTIFY: HUD_Panel_UpdatePosSize(notify) break;\
- case HUD_PANEL_TIMER: HUD_Panel_UpdatePosSize(timer) break;\
- case HUD_PANEL_RADAR: HUD_Panel_UpdatePosSize(radar) break;\
- case HUD_PANEL_SCORE: HUD_Panel_UpdatePosSize(score) break;\
- case HUD_PANEL_RACETIMER: HUD_Panel_UpdatePosSize(racetimer) break;\
- case HUD_PANEL_VOTE: HUD_Panel_UpdatePosSize(vote) break;\
- case HUD_PANEL_MODICONS: HUD_Panel_UpdatePosSize(modicons) break;\
- case HUD_PANEL_PRESSEDKEYS: HUD_Panel_UpdatePosSize(pressedkeys) break;\
- case HUD_PANEL_CHAT: HUD_Panel_UpdatePosSize(chat) break;\
- case HUD_PANEL_ENGINEINFO: HUD_Panel_UpdatePosSize(engineinfo) break;\
- default: HUD_Panel_UpdatePosSizeForId_Part2(id)\
-}
#define KN_MAX_ENTRIES 10
// q: quoted, n: not quoted
#define HUD_Write_Cvar_n(cvar) HUD_Write(strcat("seta ", cvar, " ", cvar_string(cvar), "\n"))
#define HUD_Write_Cvar_q(cvar) HUD_Write(strcat("seta ", cvar, " \"", cvar_string(cvar), "\"\n"))
-#define HUD_Write_PanelCvar_n(cvar_suf) HUD_Write_Cvar_n(strcat("hud_panel_", panel_name, cvar_suf))
-#define HUD_Write_PanelCvar_q(cvar_suf) HUD_Write_Cvar_q(strcat("hud_panel_", panel_name, cvar_suf))
+#define HUD_Write_PanelCvar_n(cvar_suf) HUD_Write_Cvar_n(strcat("hud_panel_", panel.panel_name, cvar_suf))
+#define HUD_Write_PanelCvar_q(cvar_suf) HUD_Write_Cvar_q(strcat("hud_panel_", panel.panel_name, cvar_suf))
// Save the config
void HUD_Panel_ExportCfg(string cfgname)
{
float i;
for (i = 0; i < HUD_PANEL_NUM; ++i)
{
- HUD_Panel_GetName(i);
+ panel = hud_panel[i];
HUD_Write_PanelCvar_n("");
HUD_Write_PanelCvar_q("_pos");
HUD_Write_PanelCvar_q("_alreadyvoted_alpha");
break;
case HUD_PANEL_MODICONS:
+ HUD_Write_PanelCvar_q("_ca_layout");
HUD_Write_PanelCvar_q("_dom_layout");
+ HUD_Write_PanelCvar_q("_freezetag_layout");
break;
case HUD_PANEL_PRESSEDKEYS:
HUD_Write_PanelCvar_q("_aspect");
myTarget = myPos;
for (i = 0; i < HUD_PANEL_NUM; ++i) {
- if(i == highlightedPanel || !panel_enabled)
- continue;
-
- HUD_Panel_UpdatePosSizeForId(i);
+ panel = hud_panel[i];
+ if(panel == highlightedPanel) continue;
+ HUD_Panel_UpdatePosSize()
+ if(!panel_enabled) continue;
panel_pos -= '1 1 0' * panel_bg_border;
panel_size += '2 2 0' * panel_bg_border;
void HUD_Panel_SetPos(vector pos)
{
- HUD_Panel_UpdatePosSizeForId(highlightedPanel);
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize()
vector mySize;
mySize = panel_size;
string s;
s = strcat(ftos(pos_x/vid_conwidth), " ", ftos(pos_y/vid_conheight));
- HUD_Panel_GetName(highlightedPanel);
- cvar_set(strcat("hud_panel_", panel_name, "_pos"), s);
+ cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
}
// check if resize will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
ratio = mySize_x/mySize_y;
for (i = 0; i < HUD_PANEL_NUM; ++i) {
- if(i == highlightedPanel || !panel_enabled)
- continue;
-
- HUD_Panel_UpdatePosSizeForId(i);
+ panel = hud_panel[i];
+ if(panel == highlightedPanel) continue;
+ HUD_Panel_UpdatePosSize()
+ if(!panel_enabled) continue;
panel_pos -= '1 1 0' * panel_bg_border;
panel_size += '2 2 0' * panel_bg_border;
void HUD_Panel_SetPosSize(vector mySize)
{
- HUD_Panel_UpdatePosSizeForId(highlightedPanel);
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize()
vector resizeorigin;
resizeorigin = panel_click_resizeorigin;
local noref vector myPos; // fteqcc sucks
mySize_x = max(0.025 * vid_conwidth, mySize_x);
mySize_y = max(0.025 * vid_conheight, mySize_y);
- if(highlightedPanel == HUD_PANEL_CHAT) // some panels have their own restrictions, like the chat panel (which actually only moves the engine chat print around). Looks bad if it's too small.
+ if(highlightedPanel == HUD_PANEL(CHAT)) // some panels have their own restrictions, like the chat panel (which actually only moves the engine chat print around). Looks bad if it's too small.
{
mySize_x = max(17 * autocvar_con_chatsize, mySize_x);
mySize_y = max(2 * autocvar_con_chatsize + 2 * panel_bg_padding, mySize_y);
//if(cvar("hud_configure_checkcollisions_debug"))
//drawfill(myPos, mySize, '0 1 0', .3, DRAWFLAG_NORMAL);
- HUD_Panel_GetName(highlightedPanel);
string s;
s = strcat(ftos(mySize_x/vid_conwidth), " ", ftos(mySize_y/vid_conheight));
- cvar_set(strcat("hud_panel_", panel_name, "_size"), s);
+ cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
s = strcat(ftos(myPos_x/vid_conwidth), " ", ftos(myPos_y/vid_conheight));
- cvar_set(strcat("hud_panel_", panel_name, "_pos"), s);
+ cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
}
float pressed_key_time;
vector highlightedPanel_initial_pos, highlightedPanel_initial_size;
void HUD_Panel_Arrow_Action(float nPrimary)
{
- if (highlightedPanel == -1)
+ if(!highlightedPanel)
return;
hud_configure_checkcollisions = (!(hudShiftState & S_CTRL) && autocvar_hud_configure_checkcollisions);
step = (step / 64) * (1 + 2 * (time - pressed_key_time));
}
- HUD_Panel_UpdatePosSizeForId(highlightedPanel);
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize()
highlightedPanel_initial_pos = panel_pos;
highlightedPanel_initial_size = panel_size;
HUD_Panel_SetPos(pos);
}
- HUD_Panel_UpdatePosSizeForId(highlightedPanel);
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize()
if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size)
{
vector prevMouseClickedPos; // pos during previous left mouse click, to check for doubleclicks
void HUD_Panel_EnableMenu();
-float tab_panels[HUD_PANEL_NUM];
-float tab_panel, tab_backward;
+entity tab_panels[HUD_PANEL_MAX];
+entity tab_panel;
vector tab_panel_pos;
+float tab_backward;
void HUD_Panel_FirstInDrawQ(float id);
void reset_tab_panels()
{
int i;
for(i = 0; i < HUD_PANEL_NUM; ++i)
- tab_panels[i] = -1;
+ tab_panels[i] = world;
}
float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary)
{
{
if (bInputType == 1) //ctrl has been released
{
- if (tab_panel != -1)
+ if (tab_panel)
{
//switch to selected panel
highlightedPanel = tab_panel;
highlightedAction = 0;
- HUD_Panel_FirstInDrawQ(highlightedPanel);
+ HUD_Panel_FirstInDrawQ(highlightedPanel.panel_id);
}
- tab_panel = -1;
+ tab_panel = world;
reset_tab_panels();
}
}
//(it should only after every other panel of the hud)
//It's a minor bug anyway, we can live with it
- float starting_panel;
- float old_tab_panel = tab_panel;
- if (tab_panel == -1) //first press of TAB
+ entity starting_panel;
+ entity old_tab_panel = tab_panel;
+ if (!tab_panel) //first press of TAB
{
- if (highlightedPanel != -1)
- HUD_Panel_UpdatePosSizeForId(highlightedPanel)
+ if (highlightedPanel)
+ {
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize()
+ }
else
panel_pos = '0 0 0';
- starting_panel = highlightedPanel; //can be -1, it means no starting panel
+ starting_panel = highlightedPanel;
tab_panel_pos = panel_pos; //to compute level
}
else
level = floor(tab_panel_pos_y / level_height) * level_height; //starting level
candidate_pos_x = (!tab_backward) ? vid_conwidth : 0;
start_pos_x = tab_panel_pos_x;
- tab_panel = -1;
+ tab_panel = world;
k=0;
while(++k)
{
for(i = 0; i < HUD_PANEL_NUM; ++i)
{
- if (i == tab_panels[i] || i == starting_panel)
+ panel = hud_panel[i];
+ if (panel == tab_panels[i] || panel == starting_panel)
continue;
- HUD_Panel_UpdatePosSizeForId(i)
+ HUD_Panel_UpdatePosSize()
if (panel_pos_y >= level && (panel_pos_y - level) < level_height)
if ( ( !tab_backward && panel_pos_x >= start_pos_x && (panel_pos_x < candidate_pos_x || (panel_pos_x == candidate_pos_x && panel_pos_y <= candidate_pos_y)) )
|| ( tab_backward && panel_pos_x <= start_pos_x && (panel_pos_x > candidate_pos_x || (panel_pos_x == candidate_pos_x && panel_pos_y >= candidate_pos_y)) ) )
{
- tab_panel = i;
+ tab_panel = panel;
tab_panel_pos = candidate_pos = panel_pos;
}
}
- if (tab_panel != -1)
+ if (tab_panel)
break;
if (k == LEVELS_NUM) //tab_panel not found
{
reset_tab_panels();
- if (old_tab_panel == -2) //this prevents an infinite loop (should not happen normally)
+ if (!old_tab_panel)
{
- tab_panel = -1;
+ tab_panel = world;
return true;
}
starting_panel = old_tab_panel;
- old_tab_panel = -2;
+ old_tab_panel = world;
goto find_tab_panel; //u must find tab_panel!
}
if (!tab_backward)
}
}
- tab_panels[tab_panel] = tab_panel;
+ tab_panels[tab_panel.panel_id] = tab_panel;
}
else if(nPrimary == K_SPACE && hudShiftState & S_CTRL) // enable/disable highlighted panel or dock
{
if (bInputType == 1 || mouseClicked)
return true;
- if (highlightedPanel != -1)
- {
- HUD_Panel_GetName(highlightedPanel);
- cvar_set(strcat("hud_panel_", panel_name), ftos(!(panel_enabled)));
- }
+ if (highlightedPanel)
+ cvar_set(strcat("hud_panel_", highlightedPanel.panel_name), ftos(!cvar(strcat("hud_panel_", highlightedPanel.panel_name))));
else
cvar_set(strcat("hud_dock"), (autocvar_hud_dock == "") ? "dock" : "");
}
if (bInputType == 1 || mouseClicked)
return true;
- if (highlightedPanel != -1)
+ if (highlightedPanel)
{
- HUD_Panel_UpdatePosSizeForId(highlightedPanel);
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize()
panel_size_copied = panel_size;
- highlightedPanel_copied = highlightedPanel;
}
}
else if(nPrimary == 'v' && hudShiftState & S_CTRL) // past copied size on the highlighted panel
if (bInputType == 1 || mouseClicked)
return true;
- if (highlightedPanel_copied == -1 || highlightedPanel == -1)
+ if (panel_size_copied == '0 0 0' || !highlightedPanel)
return true;
- HUD_Panel_UpdatePosSizeForId(highlightedPanel);
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize()
// reduce size if it'd go beyond screen boundaries
vector tmp_size = panel_size_copied;
highlightedPanel_backup = highlightedPanel;
s = strcat(ftos(tmp_size_x/vid_conwidth), " ", ftos(tmp_size_y/vid_conheight));
- HUD_Panel_GetName(highlightedPanel);
- cvar_set(strcat("hud_panel_", panel_name, "_size"), s);
+ cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
}
else if(nPrimary == 'z' && hudShiftState & S_CTRL) // undo last action
{
if (bInputType == 1 || mouseClicked)
return true;
//restore previous values
- if (highlightedPanel_backup != -1)
+ if (highlightedPanel_backup)
{
- HUD_Panel_GetName(highlightedPanel_backup);
s = strcat(ftos(panel_pos_backup_x/vid_conwidth), " ", ftos(panel_pos_backup_y/vid_conheight));
- cvar_set(strcat("hud_panel_", panel_name, "_pos"), s);
+ cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_pos"), s);
s = strcat(ftos(panel_size_backup_x/vid_conwidth), " ", ftos(panel_size_backup_y/vid_conheight));
- cvar_set(strcat("hud_panel_", panel_name, "_size"), s);
- highlightedPanel_backup = -1;
+ cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_size"), s);
+ highlightedPanel_backup = world;
}
}
else if(nPrimary == K_UPARROW || nPrimary == K_DOWNARROW || nPrimary == K_LEFTARROW || nPrimary == K_RIGHTARROW)
{
if (bInputType == 1)
return true;
- if (highlightedPanel != -1)
+ if (highlightedPanel)
HUD_Panel_EnableMenu();
}
else if(hit_con_bind)
i = panel_order[j];
j += 1;
- HUD_Panel_UpdatePosSizeForId(i);
+ panel = hud_panel[i];
+ HUD_Panel_UpdatePosSize()
border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
i = panel_order[j];
j += 1;
- HUD_Panel_UpdatePosSizeForId(i);
+ panel = hud_panel[i];
+ HUD_Panel_UpdatePosSize()
border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
// move
if(allow_move && mousepos_x > panel_pos_x && mousepos_y > panel_pos_y && mousepos_x < panel_pos_x + panel_size_x && mousepos_y < panel_pos_y + panel_size_y)
{
- highlightedPanel = i;
+ highlightedPanel = hud_panel[i];
HUD_Panel_FirstInDrawQ(i);
highlightedAction = 1;
panel_click_distance = mousepos - panel_pos;
// resize from topleft border
else if(mousepos_x >= panel_pos_x - border && mousepos_y >= panel_pos_y - border && mousepos_x <= panel_pos_x + 0.5 * panel_size_x && mousepos_y <= panel_pos_y + 0.5 * panel_size_y)
{
- highlightedPanel = i;
+ highlightedPanel = hud_panel[i];
HUD_Panel_FirstInDrawQ(i);
highlightedAction = 2;
resizeCorner = 1;
// resize from topright border
else if(mousepos_x >= panel_pos_x + 0.5 * panel_size_x && mousepos_y >= panel_pos_y - border && mousepos_x <= panel_pos_x + panel_size_x + border && mousepos_y <= panel_pos_y + 0.5 * panel_size_y)
{
- highlightedPanel = i;
+ highlightedPanel = hud_panel[i];
HUD_Panel_FirstInDrawQ(i);
highlightedAction = 2;
resizeCorner = 2;
// resize from bottomleft border
else if(mousepos_x >= panel_pos_x - border && mousepos_y >= panel_pos_y + 0.5 * panel_size_y && mousepos_x <= panel_pos_x + 0.5 * panel_size_x && mousepos_y <= panel_pos_y + panel_size_y + border)
{
- highlightedPanel = i;
+ highlightedPanel = hud_panel[i];
HUD_Panel_FirstInDrawQ(i);
highlightedAction = 2;
resizeCorner = 3;
// resize from bottomright border
else if(mousepos_x >= panel_pos_x + 0.5 * panel_size_x && mousepos_y >= panel_pos_y + 0.5 * panel_size_y && mousepos_x <= panel_pos_x + panel_size_x + border && mousepos_y <= panel_pos_y + panel_size_y + border)
{
- highlightedPanel = i;
+ highlightedPanel = hud_panel[i];
HUD_Panel_FirstInDrawQ(i);
highlightedAction = 2;
resizeCorner = 4;
return;
}
}
- highlightedPanel = -1;
+ highlightedPanel = world;
highlightedAction = 0;
}
{
menu_enabled = 2;
menu_enabled_time = time;
- HUD_Panel_GetName(highlightedPanel);
- localcmd("menu_showhudoptions ", panel_name, "\n");
+ localcmd("menu_showhudoptions ", highlightedPanel.panel_name, "\n");
}
float mouse_over_panel;
void HUD_Panel_Mouse()
{
if(prevMouseClicked == 0)
{
- if (tab_panel != -1)
+ if (tab_panel)
{
//stop ctrl-tab selection
- tab_panel = -1;
+ tab_panel = world;
reset_tab_panels();
}
HUD_Panel_Highlight(mouseClicked & S_MOUSE1); // sets highlightedPanel, highlightedAction, panel_click_distance, panel_click_resizeorigin
- // and calls HUD_Panel_UpdatePosSizeForId() for the highlighted panel
- if (highlightedPanel != -1)
+ // and calls HUD_Panel_UpdatePosSize() for the highlighted panel
+ if (highlightedPanel)
{
highlightedPanel_initial_pos = panel_pos;
highlightedPanel_initial_size = panel_size;
}
// doubleclick check
- if ((mouseClicked & S_MOUSE1) && time - prevMouseClickedTime < 0.4 && highlightedPanel != -1 && prevMouseClickedPos == mousepos)
+ if ((mouseClicked & S_MOUSE1) && time - prevMouseClickedTime < 0.4 && highlightedPanel && prevMouseClickedPos == mousepos)
{
mouseClicked = 0; // to prevent spam, I guess.
HUD_Panel_EnableMenu();
}
}
else
- HUD_Panel_UpdatePosSizeForId(highlightedPanel);
+ {
+ panel = highlightedPanel;
+ HUD_Panel_UpdatePosSize()
+ }
- if (highlightedPanel != -1)
+ if (highlightedPanel)
{
drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .1, DRAWFLAG_NORMAL);
if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size)
mouse_over_panel = 0;
else
mouse_over_panel = HUD_Panel_Check_Mouse_Pos(TRUE);
- if (mouse_over_panel && tab_panel == -1)
+ if (mouse_over_panel && !tab_panel)
drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .1, DRAWFLAG_NORMAL);
}
// draw cursor after performing move/resize to have the panel pos/size updated before mouse_over_panel
print(sprintf(
strcat(
"Restart_Notifications(): Restarting %d notifications... ",
- "Counts: MSG_INFO = %d, MSG_CENTER = %d, MSG_MULTI = %d\n"
+ "Counts: MSG_ANNCE = %d, MSG_INFO = %d, MSG_CENTER = %d, MSG_MULTI = %d\n"
),
(
+ NOTIF_ANNCE_COUNT +
NOTIF_INFO_COUNT +
NOTIF_CENTER_COUNT +
NOTIF_MULTI_COUNT
- ),
+ ),
+ NOTIF_ANNCE_COUNT,
NOTIF_INFO_COUNT,
NOTIF_CENTER_COUNT,
NOTIF_MULTI_COUNT
const float TE_CSQC_LIGHTNINGARC = 105;
const float TE_CSQC_TEAMNAGGER = 106;
const float TE_CSQC_PINGPLREPORT = 107;
-const float TE_CSQC_ANNOUNCE = 108;
-const float TE_CSQC_TARGET_MUSIC = 109;
-const float TE_CSQC_WEAPONCOMPLAIN = 110;
-const float TE_CSQC_NEX_SCOPE = 111;
-const float TE_CSQC_MINELAYER_MAXMINES = 112;
-const float TE_CSQC_HAGAR_MAXROCKETS = 113;
-const float TE_CSQC_VEHICLESETUP = 114;
-const float TE_CSQC_SVNOTICE = 115;
+const float TE_CSQC_TARGET_MUSIC = 108;
+const float TE_CSQC_WEAPONCOMPLAIN = 109;
+const float TE_CSQC_NEX_SCOPE = 110;
+const float TE_CSQC_MINELAYER_MAXMINES = 111;
+const float TE_CSQC_HAGAR_MAXROCKETS = 112;
+const float TE_CSQC_VEHICLESETUP = 113;
+const float TE_CSQC_SVNOTICE = 114;
const float RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder
const float RACE_NET_CHECKPOINT_CLEAR = 1;
const float STAT_SECRETS_FOUND = 71;
const float STAT_RESPAWN_TIME = 72;
+const float STAT_ROUNDSTARTTIME = 73;
// mod stats (1xx)
const float STAT_REDALIVE = 100;
float WR_PLAYERDEATH = 13; // (SVQC) does not need to do anything
float WR_GONETHINK = 14; // (SVQC) logic to run every frame, also if no longer having the weapon as long as the switch away has not been performed
-float HUD_PANEL_WEAPONS = 0;
-float HUD_PANEL_AMMO = 1;
-float HUD_PANEL_POWERUPS = 2;
-float HUD_PANEL_HEALTHARMOR = 3;
-float HUD_PANEL_NOTIFY = 4;
-float HUD_PANEL_TIMER = 5;
-float HUD_PANEL_RADAR = 6;
-float HUD_PANEL_SCORE = 7;
-float HUD_PANEL_RACETIMER = 8;
-float HUD_PANEL_VOTE = 9;
-float HUD_PANEL_MODICONS = 10;
-float HUD_PANEL_PRESSEDKEYS = 11;
-float HUD_PANEL_CHAT = 12;
-float HUD_PANEL_ENGINEINFO = 13;
-float HUD_PANEL_INFOMESSAGES = 14;
-float HUD_PANEL_PHYSICS = 15;
-float HUD_PANEL_CENTERPRINT = 16;
-float HUD_PANEL_NUM = 17; // always last panel id + 1, please increment when adding a new panel
-
-string HUD_PANELNAME_WEAPONS = "weapons";
-string HUD_PANELNAME_AMMO = "ammo";
-string HUD_PANELNAME_POWERUPS = "powerups";
-string HUD_PANELNAME_HEALTHARMOR = "healtharmor";
-string HUD_PANELNAME_NOTIFY = "notify";
-string HUD_PANELNAME_TIMER = "timer";
-string HUD_PANELNAME_RADAR = "radar";
-string HUD_PANELNAME_SCORE = "score";
-string HUD_PANELNAME_RACETIMER = "racetimer";
-string HUD_PANELNAME_VOTE = "vote";
-string HUD_PANELNAME_MODICONS = "modicons";
-string HUD_PANELNAME_PRESSEDKEYS = "pressedkeys";
-string HUD_PANELNAME_CHAT = "chat";
-string HUD_PANELNAME_ENGINEINFO = "engineinfo";
-string HUD_PANELNAME_INFOMESSAGES = "infomessages";
-string HUD_PANELNAME_PHYSICS = "physics";
-string HUD_PANELNAME_CENTERPRINT = "centerprint";
-
#define SERVERFLAG_ALLOW_FULLBRIGHT 1
#define SERVERFLAG_TEAMPLAY 2
#define SERVERFLAG_PLAYERSTATS 4
s = cdr(s);
}
+ if(pWantedType == MAPINFO_TYPE_CA)
+ {
+ sa = car(s);
+ if(sa != "")
+ cvar_set("g_ca_teams", sa);
+ s = cdr(s);
+ }
+
+ if(pWantedType == MAPINFO_TYPE_FREEZETAG)
+ {
+ sa = car(s);
+ if(sa != "")
+ cvar_set("g_freezetag_teams", sa);
+ s = cdr(s);
+ }
+
if(pWantedType == MAPINFO_TYPE_CTF)
{
sa = car(s);
cvar_set("leadlimit", cvar_defstring("leadlimit"));
cvar_set("fraglimit", cvar_defstring("fraglimit"));
cvar_set("g_tdm_teams", cvar_defstring("g_tdm_teams"));
+ cvar_set("g_ca_teams", cvar_defstring("g_ca_teams"));
+ cvar_set("g_freezetag_teams", cvar_defstring("g_freezetag_teams"));
cvar_set("g_keyhunt_teams", cvar_defstring("g_keyhunt_teams"));
cvar_set("g_domination_default_teams", cvar_defstring("g_domination_default_teams"));
cvar_set("g_race_qualifying_timelimit", cvar_defstring("g_race_qualifying_timelimit"));
else if(k == "teams")
{
cvar_set("g_tdm_teams", v);
+ cvar_set("g_ca_teams", v);
+ cvar_set("g_freezetag_teams", v);
cvar_set("g_keyhunt_teams", v);
cvar_set("g_domination_default_teams", v);
}
{
switch(net_type)
{
+ case MSG_ANNCE: return "MSG_ANNCE";
case MSG_INFO: return "MSG_INFO";
case MSG_CENTER: return "MSG_CENTER";
case MSG_CENTER_CPID: return "MSG_CENTER_CPID";
{
switch(net_type)
{
+ case MSG_ANNCE: return msg_annce_notifs[net_name - 1];
case MSG_INFO: return msg_info_notifs[net_name - 1];
case MSG_CENTER: return msg_center_notifs[net_name - 1];
case MSG_MULTI: return msg_multi_notifs[net_name - 1];
{ checkargs = sprintf("Improper name: %d!", net_name); } break; }
switch(net_type)
{
+ CHECKARG_TYPENAME(ANNCE)
CHECKARG_TYPENAME(INFO)
CHECKARG_TYPENAME(CENTER)
CHECKARG_TYPENAME(MULTI)
void Destroy_Notification_Entity(entity notif)
{
if(notif.nent_name != "") { strunzone(notif.nent_name); }
+ if(notif.nent_snd != "") { strunzone(notif.nent_snd); }
if(notif.nent_args != "") { strunzone(notif.nent_args); }
if(notif.nent_hudargs != "") { strunzone(notif.nent_hudargs); }
if(notif.nent_icon != "") { strunzone(notif.nent_icon); }
#endif
// kill all real notification entities
+ DESTROY_LOOP(MSG_ANNCE, NOTIF_ANNCE_COUNT)
DESTROY_LOOP(MSG_INFO, NOTIF_INFO_COUNT)
DESTROY_LOOP(MSG_CENTER, NOTIF_CENTER_COUNT)
DESTROY_LOOP(MSG_MULTI, NOTIF_MULTI_COUNT)
float typeid,
float nameid,
string namestring,
+ float anncename,
float infoname,
float centername,
+ float channel,
+ string snd,
+ float vol,
+ float position,
float strnum,
float flnum,
string args,
string typestring = "";
switch(typeid)
{
+ case MSG_ANNCE:
+ {
+ typestring = "MSG_ANNCE";
+ msg_annce_notifs[nameid - 1] = notif;
+ notif.classname = "msg_annce_notification";
+ break;
+ }
case MSG_INFO:
{
typestring = "MSG_INFO";
if(msg_is_multi)
{
// Set MSG_MULTI string/float counts
- if((infoname == NO_MSG) && (centername == NO_MSG))
+ if((anncename == NO_MSG) && (infoname == NO_MSG) && (centername == NO_MSG))
{
print(sprintf(
strcat(
}
else
{
+ // announcements don't actually need any arguments, so lets not even count them.
+ if(anncename != NO_MSG) { notif.nent_msgannce = msg_annce_notifs[anncename - 1]; }
+
float infoname_stringcount = 0, infoname_floatcount = 0;
float centername_stringcount = 0, centername_floatcount = 0;
notif.nent_floatcount = max(infoname_floatcount, centername_floatcount);
}
}
+ else if(typeid == MSG_ANNCE)
+ {
+ // Set MSG_ANNCE information and handle precaching
+ #ifdef CSQC
+ if not(GENTLE && (var_cvar == 1))
+ {
+ if(snd != "")
+ {
+ if(notif.nent_enabled)
+ {
+ precache_sound(sprintf("announcer/%s/%s.wav", autocvar_cl_announcer, snd));
+ notif.nent_channel = channel;
+ notif.nent_snd = strzone(snd);
+ notif.nent_vol = vol;
+ notif.nent_position = position;
+ }
+ }
+ else
+ {
+ print(sprintf(
+ strcat(
+ "^1NOTIFICATION WITH NO SOUND: ",
+ "^7net_type = %s, net_name = %s.\n"
+ ),
+ typestring,
+ namestring
+ ));
+ notif_error = TRUE;
+ }
+ }
+ else { notif.nent_enabled = FALSE; }
+ #else
+ notif.nent_enabled = FALSE;
+ #endif
+ }
else
{
// Set MSG_INFO and MSG_CENTER string/float counts
// This is not necessary, and does not matter if they vary between config versions,
// it is just a semi-helpful tool for those who want to manually change their user settings.
+ NOTIF_WRITE(sprintf("\n// MSG_ANNCE notifications (count = %d):\n", NOTIF_ANNCE_COUNT));
+ for(i = 1; i <= NOTIF_ANNCE_COUNT; ++i)
+ {
+ e = Get_Notif_Ent(MSG_ANNCE, i);
+ if not(e) { backtrace("Dump_Notifications(): Missing notification entity!\n"); return; }
+ NOTIF_WRITE_ENTITY(e.nent_name, e.nent_default, "Notification control cvar: 0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled)");
+ }
+
NOTIF_WRITE(sprintf("\n// MSG_INFO notifications (count = %d):\n", NOTIF_INFO_COUNT));
for(i = 1; i <= NOTIF_INFO_COUNT; ++i)
{
NOTIF_WRITE_HARDCODED("ctf_capture_verbose", "0", "Show extra information when someone captures a flag");
NOTIF_WRITE_HARDCODED("ctf_pickup_enemy_verbose", "0", "Show extra information if an enemy picks up a flag");
NOTIF_WRITE_HARDCODED("ctf_pickup_team_verbose", "0", "Show extra information if a team mate picks up a flag");
+ NOTIF_WRITE_HARDCODED("debug", "0", "Print extra debug information on all notification function calls (Requires -DNOTIFICATIONS_DEBUG flag to be enabled on QCSRC compilation)... 0 = disabled, 1 = dprint, 2 = print");
NOTIF_WRITE_HARDCODED("errors_are_fatal", "1", "If a notification fails upon initialization, cause a Host_Error to stop the program");
NOTIF_WRITE_HARDCODED("frag_verbose", "1", "Show extra information when you frag someone (or when you are fragged");
NOTIF_WRITE_HARDCODED("item_centerprinttime", "1.5", "How long to show item information centerprint messages (like 'You got the Electro' or such)");
NOTIF_WRITE(sprintf(
strcat(
"\n// Notification counts (total = %d): ",
- "MSG_INFO = %d, MSG_CENTER = %d, MSG_MULTI = %d\n"
+ "MSG_ANNCE = %d, MSG_INFO = %d, MSG_CENTER = %d, MSG_MULTI = %d\n"
),
(
+ NOTIF_ANNCE_COUNT +
NOTIF_INFO_COUNT +
NOTIF_CENTER_COUNT +
NOTIF_MULTI_COUNT
- ),
+ ),
+ NOTIF_ANNCE_COUNT,
NOTIF_INFO_COUNT,
NOTIF_CENTER_COUNT,
NOTIF_MULTI_COUNT
// Frontend Notification Pushing
// ===============================
+#ifdef NOTIFICATIONS_DEBUG
+void Debug_Notification(string input)
+{
+ switch(autocvar_notification_debug)
+ {
+ case 1: { dprint(input); break; }
+ case 2: { print(input); break; }
+ }
+}
+#endif
+
string Local_Notification_sprintf(
string input, string args,
string s1, string s2, string s3, string s4,
float f1, float f2, float f3, float f4)
{
#ifdef NOTIFICATIONS_DEBUG
- dprint(sprintf(
+ Debug_Notification(sprintf(
"Local_Notification_sprintf('%s^7', '%s', %s, %s);\n",
MakeConsoleSafe(input),
args,
}
#ifdef CSQC
+void Local_Notification_sound(
+ float soundchannel, string soundfile,
+ float soundvolume, float soundposition)
+{
+ if((soundfile != prev_soundfile) || (time >= (prev_soundtime + autocvar_cl_announcer_antispam)))
+ {
+ #ifdef NOTIFICATIONS_DEBUG
+ Debug_Notification(sprintf(
+ "Local_Notification_sound(world, %f, '%s', %f, %f);\n",
+ soundchannel,
+ sprintf(
+ "announcer/%s/%s.wav",
+ autocvar_cl_announcer,
+ soundfile
+ ),
+ soundvolume,
+ soundposition
+ ));
+ #endif
+
+ sound(
+ world,
+ soundchannel,
+ sprintf(
+ "announcer/%s/%s.wav",
+ autocvar_cl_announcer,
+ soundfile
+ ),
+ soundvolume,
+ soundposition
+ );
+
+ if(prev_soundfile) { strunzone(prev_soundfile); }
+ prev_soundfile = strzone(soundfile);
+ prev_soundtime = time;
+ }
+ else
+ {
+ #ifdef NOTIFICATIONS_DEBUG
+ Debug_Notification(sprintf(
+ "Local_Notification_sound(world, %f, '%s', %f, %f) ^1BLOCKED BY ANTISPAM:^7 prevsnd: '%s', time/prevtime: %f, limit: %f\n",
+ soundchannel,
+ sprintf(
+ "announcer/%s/%s.wav",
+ autocvar_cl_announcer,
+ soundfile
+ ),
+ soundvolume,
+ soundposition,
+ prev_soundfile,
+ (time - prev_soundtime),
+ autocvar_cl_announcer_antispam
+ ));
+ #endif
+ }
+}
void Local_Notification_HUD_Notify_Push(
string icon, string hudargs,
string s1, string s2, string s3, string s4)
}
}
#ifdef NOTIFICATIONS_DEBUG
- dprint(sprintf(
+ Debug_Notification(sprintf(
"Local_Notification_HUD_Notify_Push('%s^7', '%s', %s, %s);\n",
icon,
hudargs,
}
}
#ifdef NOTIFICATIONS_DEBUG
- dprint(sprintf(
+ Debug_Notification(sprintf(
"Local_Notification_centerprint_generic('%s^7', '%s', %d, %d, %d, %d);\n",
MakeConsoleSafe(input),
durcnt,
if not(notif.nent_enabled)
{
#ifdef NOTIFICATIONS_DEBUG
- dprint(sprintf(
+ Debug_Notification(sprintf(
"Local_Notification(%s, %s): Entity was disabled...\n",
Get_Notif_TypeName(net_type),
notif.nent_name
float f4 = ((3 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 3), float) : 0);
#ifdef NOTIFICATIONS_DEBUG
- dprint(sprintf(
+ Debug_Notification(sprintf(
"Local_Notification(%s, %s, %s, %s);\n",
Get_Notif_TypeName(net_type),
notif.nent_name,
switch(net_type)
{
+ case MSG_ANNCE:
+ {
+ #ifdef CSQC
+ Local_Notification_sound(
+ notif.nent_channel,
+ notif.nent_snd,
+ notif.nent_vol,
+ notif.nent_position
+ );
+ #else
+ backtrace("MSG_ANNCE on server?... Please notify Samual immediately!\n");
+ #endif
+ break;
+ }
+
case MSG_INFO:
{
print(
f1, f2, f3, f4);
}
#ifdef CSQC
+ if(notif.nent_msgannce)
+ if(notif.nent_msgannce.nent_enabled)
+ {
+ Local_Notification_WOVA(
+ MSG_ANNCE,
+ notif.nent_msgannce.nent_id,
+ 0, 0,
+ "", "", "", "",
+ 0, 0, 0, 0);
+ }
if(notif.nent_msgcenter)
if(notif.nent_msgcenter.nent_enabled)
{
if(net_type == MSG_CENTER_CPID)
{
#ifdef NOTIFICATIONS_DEBUG
- dprint(sprintf(
+ Debug_Notification(sprintf(
"Read_Notification(%d) at %f: net_type = %s, net_name = %d\n",
is_new,
time,
if not(notif) { backtrace("Read_Notification: Could not find notification entity!\n"); return; }
#ifdef NOTIFICATIONS_DEBUG
- dprint(sprintf(
+ Debug_Notification(sprintf(
"Read_Notification(%d) at %f: net_type = %s, net_name = %s\n",
is_new,
time,
if not(self) { backtrace(sprintf("Net_Notification_Remove() at %f: Missing self!?\n", time)); return; }
#ifdef NOTIFICATIONS_DEBUG
- dprint(sprintf(
+ Debug_Notification(sprintf(
"Net_Notification_Remove() at %f: %s '%s - %s' notification\n",
time,
((self.nent_net_name == -1) ? "Killed" : "Removed"),
if(checkargs != "") { backtrace(sprintf("Incorrect usage of Kill_Notification: %s\n", checkargs)); return; }
#ifdef NOTIFICATIONS_DEBUG
- dprint(sprintf(
+ Debug_Notification(sprintf(
"Kill_Notification(%d, '%s', %s, %d);\n",
broadcast,
client.netname,
- Get_Notif_TypeName(net_type),
+ (net_type ? Get_Notif_TypeName(net_type) : "0"),
net_name
));
#endif
{
if(net_type)
{
- if(killed_cpid != NO_CPID)
+ if((killed_cpid != NO_CPID) && (notif.nent_net_type == MSG_CENTER))
{
if(notif.owner.nent_cpid == killed_cpid)
{
float f2 = ((1 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 1), float) : 0);
float f3 = ((2 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 2), float) : 0);
float f4 = ((3 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 3), float) : 0);
- dprint(sprintf(
+ Debug_Notification(sprintf(
"Send_Notification(%d, %s, %s, %s, %s);\n",
broadcast,
Get_Notif_TypeName(net_type),
Net_LinkEntity(net_notif, FALSE, 0, Net_Write_Notification);
- if(server_is_dedicated && (broadcast == NOTIF_ALL || broadcast == NOTIF_ALL_EXCEPT) && (net_type != MSG_CENTER))
+ if(server_is_dedicated && (broadcast == NOTIF_ALL || broadcast == NOTIF_ALL_EXCEPT) && (net_type != MSG_ANNCE) && (net_type != MSG_CENTER))
{
Local_Notification_WOVA(
net_type, net_name,
entity notif = Get_Notif_Ent(net_type, net_name);
#ifdef NOTIFICATIONS_DEBUG
- dprint(sprintf(
+ Debug_Notification(sprintf(
"Send_Notification_WOVA(%d, %s, %s, %s, %s);\n",
broadcast,
Get_Notif_TypeName(net_type),
// ================================================
// main types/groups of notifications
-#define MSG_INFO 1 // "Global" information messages (sent to console, and notify panel if it has an icon)
-#define MSG_CENTER 2 // "Personal" centerprint messages
-#define MSG_CENTER_CPID 3 // Kill centerprint message
-#define MSG_MULTI 4 // Subcall MSG_INFO and/or MSG_CENTER notifications
+#define MSG_ANNCE 1 // "Global" AND "personal" announcer messages
+#define MSG_INFO 2 // "Global" information messages
+#define MSG_CENTER 3 // "Personal" centerprint messages
+#define MSG_CENTER_CPID 4 // Kill centerprint message
+#define MSG_MULTI 5 // Subcall MSG_INFO and/or MSG_CENTER notifications
#define NO_MSG -12345
float typeid,
float nameid,
string namestring,
+ float anncename,
float infoname,
float centername,
+ float channel,
+ string snd,
+ float vol,
+ float position,
float strnum,
float flnum,
string args,
void Dump_Notifications(float fh, float alsoprint);
+#ifdef NOTIFICATIONS_DEBUG
+void Debug_Notification(string input);
+#endif
+
void Local_Notification(float net_type, float net_name, ...count);
void Local_Notification_WOVA(
float net_type, float net_name,
#ifdef CSQC // CLIENT ONLY
void Read_Notification(float is_new);
+string prev_soundfile;
+float prev_soundtime;
#endif
#ifdef SVQC // SERVER ONLY
// ====================================
/*
List of all notifications (including identifiers and display information)
- Possible Tokens: default, name, infoname, centername, strnum, flnum, args, hudargs, icon, cpid, durcnt, normal, gentle
+ Possible Tokens:
+ default, name, channel, sound, volume, position,
+ anncename, infoname, centername, strnum, flnum, args,
+ hudargs, icon, cpid, durcnt, normal, gentle
Format Specifications:
+ MSG_ANNCE:
+ default: FLOAT: Default setting for whether the notification is enabled or not
+ ^-> 0 = disabled, 1 = enabled if gentle is disabled, 2 = always enabled
+ name: VAR: Name of notification
+ channel: FLOAT: Sound channel to broadcast on to
+ sound: STRING: Filename for the announcement sound
+ volume: FLOAT: Volume setting for the announcement sound
+ position: FLOAT: Attenuation/positioning value
MSG_INFO:
default: FLOAT: Default setting for whether the notification is enabled or not
^-> 0 = disabled, 1 = enabled, 2 = also print to chat box
default: FLOAT: Default setting for whether the notification is enabled or not
^-> 0 = disabled, 1 = enabled
name: VAR: Name of chaining notification
+ anncename: VAR: Name of announcer notification for reference
infoname: VAR: Name of info notification for reference
centername: VAR: Name of centerprint notification for reference
If you send a notification with mismatching arguments, Send_Notification() will error.
*/
+#define MSG_ANNCE_NOTIFICATIONS \
+ MSG_ANNCE_NOTIF(1, ANNCE_ACHIEVEMENT_AIRSHOT, CH_INFO, "airshot", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_ACHIEVEMENT_AMAZING, CH_INFO, "amazing", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_ACHIEVEMENT_AWESOME, CH_INFO, "awesome", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_ACHIEVEMENT_BOTLIKE, CH_INFO, "botlike", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_ACHIEVEMENT_ELECTROBITCH, CH_INFO, "electrobitch", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_ACHIEVEMENT_IMPRESSIVE, CH_INFO, "impressive", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_ACHIEVEMENT_YODA, CH_INFO, "yoda", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_BEGIN, CH_INFO, "begin", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_KILLSTREAK_03, CH_INFO, "03kills", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_KILLSTREAK_05, CH_INFO, "05kills", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_KILLSTREAK_10, CH_INFO, "10kills", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_KILLSTREAK_15, CH_INFO, "15kills", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_KILLSTREAK_20, CH_INFO, "20kills", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_KILLSTREAK_25, CH_INFO, "25kills", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_KILLSTREAK_30, CH_INFO, "30kills", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_MINSTAGIB_LASTSECOND, CH_INFO, "lastsecond", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_MINSTAGIB_NARROWLY, CH_INFO, "narrowly", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_MINSTAGIB_TERMINATED, CH_INFO, "terminated", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(0, ANNCE_MULTIFRAG, CH_INFO, "multifrag", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_NUM_1, CH_INFO, "1", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_NUM_2, CH_INFO, "2", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_NUM_3, CH_INFO, "3", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_NUM_4, CH_INFO, "4", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_NUM_5, CH_INFO, "5", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_NUM_6, CH_INFO, "6", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_NUM_7, CH_INFO, "7", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_NUM_8, CH_INFO, "8", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_NUM_9, CH_INFO, "9", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_NUM_10, CH_INFO, "10", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_PREPARE, CH_INFO, "prepareforbattle", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_REMAINING_FRAG_1, CH_INFO, "1fragleft", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_REMAINING_FRAG_2, CH_INFO, "2fragsleft", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(1, ANNCE_REMAINING_FRAG_3, CH_INFO, "3fragsleft", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_REMAINING_MIN_1, CH_INFO, "1minuteremains", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_REMAINING_MIN_5, CH_INFO, "5minutesremain", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_TIMEOUT, CH_INFO, "timeoutcalled", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_VOTE_ACCEPT, CH_INFO, "voteaccept", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_VOTE_CALL, CH_INFO, "votecall", VOL_BASEVOICE, ATTN_NONE) \
+ MSG_ANNCE_NOTIF(2, ANNCE_VOTE_FAIL, CH_INFO, "votefail", VOL_BASEVOICE, ATTN_NONE)
+
#define MULTITEAM_INFO(default,prefix,teams,strnum,flnum,args,hudargs,icon,normal,gentle) \
- MSG_INFO_NOTIF(default, prefix##RED, strnum, flnum, args, hudargs, sprintf(icon, strtolower(NAME_TEAM_1)), TCR(normal, COL_TEAM_1, strtoupper(NAME_TEAM_1)), TCR(gentle, COL_TEAM_1, strtoupper(NAME_TEAM_1))) \
- MSG_INFO_NOTIF(default, prefix##BLUE, strnum, flnum, args, hudargs, sprintf(icon, strtolower(NAME_TEAM_2)), TCR(normal, COL_TEAM_2, strtoupper(NAME_TEAM_2)), TCR(gentle, COL_TEAM_2, strtoupper(NAME_TEAM_2))) \
+ MSG_INFO_NOTIF(default, prefix##RED, strnum, flnum, args, hudargs, sprintf(icon, strtolower(STATIC_NAME_TEAM_1)), TCR(normal, COL_TEAM_1, strtoupper(STATIC_NAME_TEAM_1)), TCR(gentle, COL_TEAM_1, strtoupper(STATIC_NAME_TEAM_1))) \
+ MSG_INFO_NOTIF(default, prefix##BLUE, strnum, flnum, args, hudargs, sprintf(icon, strtolower(STATIC_NAME_TEAM_2)), TCR(normal, COL_TEAM_2, strtoupper(STATIC_NAME_TEAM_2)), TCR(gentle, COL_TEAM_2, strtoupper(STATIC_NAME_TEAM_2))) \
#if teams >= 3 \
- MSG_INFO_NOTIF(default, prefix##YELLOW, strnum, flnum, args, hudargs, sprintf(icon, strtolower(NAME_TEAM_3)), TCR(normal, COL_TEAM_3, strtoupper(NAME_TEAM_3)), TCR(gentle, COL_TEAM_3, strtoupper(NAME_TEAM_3))) \
+ MSG_INFO_NOTIF(default, prefix##YELLOW, strnum, flnum, args, hudargs, sprintf(icon, strtolower(STATIC_NAME_TEAM_3)), TCR(normal, COL_TEAM_3, strtoupper(STATIC_NAME_TEAM_3)), TCR(gentle, COL_TEAM_3, strtoupper(STATIC_NAME_TEAM_3))) \
#endif \
#if teams >= 4 \
- MSG_INFO_NOTIF(default, prefix##PINK, strnum, flnum, args, hudargs, sprintf(icon, strtolower(NAME_TEAM_4)), TCR(normal, COL_TEAM_4, strtoupper(NAME_TEAM_4)), TCR(gentle, COL_TEAM_4, strtoupper(NAME_TEAM_4))) \
+ MSG_INFO_NOTIF(default, prefix##PINK, strnum, flnum, args, hudargs, sprintf(icon, strtolower(STATIC_NAME_TEAM_4)), TCR(normal, COL_TEAM_4, strtoupper(STATIC_NAME_TEAM_4)), TCR(gentle, COL_TEAM_4, strtoupper(STATIC_NAME_TEAM_4))) \
#endif
#define MSG_INFO_NOTIFICATIONS \
MULTITEAM_INFO(1, INFO_CTF_CAPTURE_, 2, 1, 0, "s1", "s1", "notify_%s_captured", _("^BG%s^BG captured the ^TC^TT^BG flag\n"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VH_WAKI_DEATH, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 got caught in the blast of a Racer explosion%s%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VH_WAKI_ROCKET, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 couldn't find shelter from a Racer rocket%s%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VOID, 2, 1, "s1 s2loc spree_lost", "s1", "notify_void", _("^BG%s^K1 was in the wrong place%s%s\n"), "") \
- MULTITEAM_INFO(1, INFO_DEATH_TEAMKILL_, 4, 3, 1, "s1 s2 s3loc spree_end", "s2 s1", "notify_teamkill_%s", _("^BG%s^K1 was betrayed by ^BG%s^K1%s\n"), "") \
+ MULTITEAM_INFO(1, INFO_DEATH_TEAMKILL_, 4, 3, 1, "s1 s2 s3loc spree_end", "s2 s1", "notify_teamkill_%s", _("^BG%s^K1 was betrayed by ^BG%s^K1%s%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_FREEZETAG_FREEZE, 2, 0, "s1 s2", "", "", _("^BG%s^K1 was frozen by ^BG%s\n"), "") \
- MSG_INFO_NOTIF(1, INFO_FREEZETAG_REVIVE, 2, 0, "s1 s2", "", "", _("^BG%s^K3 was revived by ^BG%s\n"), "") \
- MULTITEAM_INFO(1, INFO_FREEZETAG_ROUND_WIN_, 4, 0, 0, "", "", "", _("^TC^TT^BG team wins the round, all other teams were frozen\n"), "") \
+ MSG_INFO_NOTIF(1, INFO_FREEZETAG_REVIVED, 2, 0, "s1 s2", "", "", _("^BG%s^K3 was revived by ^BG%s\n"), "") \
+ MSG_INFO_NOTIF(1, INFO_FREEZETAG_AUTO_REVIVED, 1, 1, "s1 f1", "", "", _("^BG%s^K3 was automatically revived after %s second(s)\n"), "") \
+ MULTITEAM_INFO(1, INFO_ROUND_TEAM_WIN_, 4, 0, 0, "", "", "", _("^TC^TT^BG team wins the round\n"), "") \
+ MSG_INFO_NOTIF(1, INFO_ROUND_PLAYER_WIN, 1, 0, "s1", "", "", _("^BG%s^BG wins the round\n"), "") \
+ MSG_INFO_NOTIF(1, INFO_ROUND_TIED, 0, 0, "", "", "", _("^BGRound tied\n"), "") \
+ MSG_INFO_NOTIF(1, INFO_ROUND_OVER, 0, 0, "", "", "", _("^BGRound over, there's no winner\n"), "") \
MSG_INFO_NOTIF(1, INFO_FREEZETAG_SELF, 1, 0, "s1", "", "", _("^BG%s^K1 froze themself\n"), "") \
MSG_INFO_NOTIF(1, INFO_GODMODE_OFF, 0, 1, "f1", "", "", _("^BGGodmode saved you %s units of damage, cheater!\n"), "") \
MSG_INFO_NOTIF(0, INFO_ITEM_WEAPON_DONTHAVE, 0, 1, "item_wepname", "", "", _("^BGYou do not have the ^F1%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_QUIT_KICK_SPECTATING, 0, 0, "", "", "", _("^F2You were kicked from the server because you are a spectator and spectators aren't allowed at the moment.\n"), "") \
MSG_INFO_NOTIF(1, INFO_QUIT_SPECTATE, 1, 0, "s1", "", "", _("^BG%s^F3 is now spectating\n"), "") \
MSG_INFO_NOTIF(1, INFO_RACE_ABANDONED, 1, 0, "s1", "", "", _("^BG%s^BG has abandoned the race\n"), "") \
- MSG_INFO_NOTIF(1, INFO_RACE_FAIL_RANKED, 1, 3, "s1 race_col f1ord race_col f2race_time race_diff", "s1", "race_newfail", _("^BG%s^BG couldn't break their %s%s^BG place record of %s%s %s\n"), "") \
- MSG_INFO_NOTIF(1, INFO_RACE_FAIL_UNRANKED, 1, 3, "s1 race_col f1ord race_col f2race_time race_diff", "s1", "race_newfail", _("^BG%s^BG couldn't break the %s%s^BG place record of %s%s %s\n"), "") \
+ MSG_INFO_NOTIF(1, INFO_RACE_FAIL_RANKED, 1, 3, "s1 race_col f1ord race_col f3race_time race_diff", "s1", "race_newfail", _("^BG%s^BG couldn't break their %s%s^BG place record of %s%s %s\n"), "") \
+ MSG_INFO_NOTIF(1, INFO_RACE_FAIL_UNRANKED, 1, 3, "s1 race_col f1ord race_col f3race_time race_diff", "s1", "race_newfail", _("^BG%s^BG couldn't break the %s%s^BG place record of %s%s %s\n"), "") \
MSG_INFO_NOTIF(1, INFO_RACE_FINISHED, 1, 0, "s1", "", "", _("^BG%s^BG has finished the race\n"), "") \
MSG_INFO_NOTIF(1, INFO_RACE_NEW_BROKEN, 2, 3, "s1 s2 race_col f1ord race_col f2race_time race_diff", "s1 s2", "race_newrankyellow", _("^BG%s^BG broke %s^BG's %s%s^BG place record with %s%s %s\n"), "") \
MSG_INFO_NOTIF(1, INFO_RACE_NEW_IMPROVED, 1, 3, "s1 race_col f1ord race_col f2race_time race_diff", "s1", "race_newtime", _("^BG%s^BG improved their %s%s^BG place record with %s%s %s\n"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_RIFLE_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponrifle", _("^BG%s%s^K1 was sniped with a Rifle by ^BG%s^K1%s%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_RIFLE_MURDER_HAIL, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponrifle", _("^BG%s%s^K1 died in ^BG%s^K1's Rifle bullet hail%s%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_RIFLE_MURDER_HAIL_PIERCING, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponrifle", _("^BG%s%s^K1 failed to hide from ^BG%s^K1's Rifle bullet hail%s%s\n"), "") \
- MSG_INFO_NOTIF(1, INFO_WEAPON_RIFLE_MURDER_HEADSHOT, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_headshot", _("^BG%s%s^K1 was shot in the head with a Rifle by ^BG%s^K1%s%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_RIFLE_MURDER_PIERCING, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponrifle", _("^BG%s%s^K1 failed to hide from ^BG%s^K1's Rifle%s%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_ROCKETLAUNCHER_MURDER_DIRECT, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponrocketlauncher", _("^BG%s%s^K1 ate ^BG%s^K1's rocket%s%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_ROCKETLAUNCHER_MURDER_SPLASH, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponrocketlauncher", _("^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_UZI_MURDER_SPRAY, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponuzi", _("^BG%s%s^K1 was riddled full of holes by ^BG%s^K1's Machine Gun%s%s\n"), "")
#define MULTITEAM_CENTER(default,prefix,teams,strnum,flnum,args,cpid,durcnt,normal,gentle) \
- MSG_CENTER_NOTIF(default, prefix##RED, strnum, flnum, args, cpid, durcnt, TCR(normal, COL_TEAM_1, strtoupper(NAME_TEAM_1)), TCR(gentle, COL_TEAM_1, strtoupper(NAME_TEAM_1))) \
- MSG_CENTER_NOTIF(default, prefix##BLUE, strnum, flnum, args, cpid, durcnt, TCR(normal, COL_TEAM_2, strtoupper(NAME_TEAM_2)), TCR(gentle, COL_TEAM_2, strtoupper(NAME_TEAM_2))) \
+ MSG_CENTER_NOTIF(default, prefix##RED, strnum, flnum, args, cpid, durcnt, TCR(normal, COL_TEAM_1, strtoupper(STATIC_NAME_TEAM_1)), TCR(gentle, COL_TEAM_1, strtoupper(STATIC_NAME_TEAM_1))) \
+ MSG_CENTER_NOTIF(default, prefix##BLUE, strnum, flnum, args, cpid, durcnt, TCR(normal, COL_TEAM_2, strtoupper(STATIC_NAME_TEAM_2)), TCR(gentle, COL_TEAM_2, strtoupper(STATIC_NAME_TEAM_2))) \
#if teams >= 3 \
- MSG_CENTER_NOTIF(default, prefix##YELLOW, strnum, flnum, args, cpid, durcnt, TCR(normal, COL_TEAM_3, strtoupper(NAME_TEAM_3)), TCR(gentle, COL_TEAM_3, strtoupper(NAME_TEAM_3))) \
+ MSG_CENTER_NOTIF(default, prefix##YELLOW, strnum, flnum, args, cpid, durcnt, TCR(normal, COL_TEAM_3, strtoupper(STATIC_NAME_TEAM_3)), TCR(gentle, COL_TEAM_3, strtoupper(STATIC_NAME_TEAM_3))) \
#endif \
#if teams >= 4 \
- MSG_CENTER_NOTIF(default, prefix##PINK, strnum, flnum, args, cpid, durcnt, TCR(normal, COL_TEAM_4, strtoupper(NAME_TEAM_4)), TCR(gentle, COL_TEAM_4, strtoupper(NAME_TEAM_4))) \
+ MSG_CENTER_NOTIF(default, prefix##PINK, strnum, flnum, args, cpid, durcnt, TCR(normal, COL_TEAM_4, strtoupper(STATIC_NAME_TEAM_4)), TCR(gentle, COL_TEAM_4, strtoupper(STATIC_NAME_TEAM_4))) \
#endif
#define MSG_CENTER_NOTIFICATIONS \
- MSG_CENTER_NOTIF(1, CENTER_ARENA_BEGIN, 0, 0, "", CPID_ARENA, "2 0", _("^F4Begin!"), "") \
- MSG_CENTER_NOTIF(1, CENTER_ARENA_NEEDPLAYER, 0, 0, "", CPID_ARENA, "2 0", _("^BGNeed at least 1 player in each team to play Clan Arena!"), "") \
- MSG_CENTER_NOTIF(1, CENTER_ARENA_ROUNDSTART, 0, 1, "", CPID_ARENA, "1 f1", _("^F4Round will start in ^COUNT"), "") \
MSG_CENTER_NOTIF(1, CENTER_ASSAULT_ATTACKING, 0, 0, "", CPID_ASSAULT_ROLE, "0 0", _("^BGYou are attacking!"), "") \
MSG_CENTER_NOTIF(1, CENTER_ASSAULT_DEFENDING, 0, 0, "", CPID_ASSAULT_ROLE, "0 0", _("^BGYou are defending!"), "") \
- MSG_CENTER_NOTIF(1, CENTER_COUNTDOWN_BEGIN, 0, 0, "", CPID_GAMESTART, "2 0", _("^F4Begin!"), "") \
- MSG_CENTER_NOTIF(1, CENTER_COUNTDOWN_GAMESTART, 0, 1, "", CPID_GAMESTART, "1 f1", _("^F4Game starts in ^COUNT"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_COUNTDOWN_BEGIN, 0, 0, "", CPID_ROUND, "2 0", _("^F4Begin!"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_COUNTDOWN_GAMESTART, 0, 1, "", CPID_ROUND, "1 f1", _("^F4Game starts in ^COUNT"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_COUNTDOWN_ROUNDSTART, 0, 1, "", CPID_ROUND, "1 f1", _("^F4Round starts in ^COUNT"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_COUNTDOWN_ROUNDSTOP, 0, 0, "", CPID_ROUND, "2 0", _("^F4Round cannot start"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_ROUND_TIED, 0, 0, "", CPID_ROUND, "0 0", _("^BGRound tied"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_ROUND_OVER, 0, 0, "", CPID_ROUND, "0 0", _("^BGRound over, there's no winner"), "") \
MSG_CENTER_NOTIF(1, CENTER_CTF_CAPTURESHIELD_FREE, 0, 0, "", CPID_CTF_CAPSHIELD, "0 0", _("^BGYou are now free.\n^BGFeel free to ^F2try to capture^BG the flag again\n^BGif you think you will succeed."), "") \
MSG_CENTER_NOTIF(1, CENTER_CTF_CAPTURESHIELD_SHIELDED, 0, 0, "", CPID_CTF_CAPSHIELD, "0 0", _("^BGYou are now ^F1shielded^BG from the flag\n^BGfor ^F2too many unsuccessful attempts^BG to capture.\n^BGMake some defensive scores before trying again."), "") \
MULTITEAM_CENTER(1, CENTER_CTF_CAPTURE_, 2, 0, 0, "", CPID_CTF_LOWPRIO, "0 0", _("^BGYou captured the ^TC^TT^BG flag!"), "") \
MSG_CENTER_NOTIF(1, CENTER_DEATH_TEAMKILL_FRAG, 1, 0, "s1", NO_CPID, "0 0", _("^K1Moron! You fragged ^BG%s^K1, a team mate!"), _("^K1Moron! You went against ^BG%s^K1, a team mate!")) \
MSG_CENTER_NOTIF(1, CENTER_DEATH_TEAMKILL_FRAGGED, 1, 0, "s1", NO_CPID, "0 0", _("^K1You were fragged by ^BG%s^K1, a team mate"), _("^K1You were scored against by ^BG%s^K1, a team mate")) \
MSG_CENTER_NOTIF(1, CENTER_DISCONNECT_IDLING, 0, 1, "", CPID_IDLING, "1 f1", _("^K1Stop idling!\n^BGDisconnecting in ^COUNT..."), "") \
+ MSG_CENTER_NOTIF(1, CENTER_EXTRALIVES, 0, 0, "", NO_CPID, "0 0", _("^F2You picked up some extra lives"), "") \
MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_FREEZE, 1, 0, "s1", NO_CPID, "0 0", _("^K3You froze ^BG%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_FROZEN, 1, 0, "s1", NO_CPID, "0 0", _("^K1You were frozen by ^BG%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVE, 1, 0, "s1", NO_CPID, "0 0", _("^K3You revived ^BG%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVED, 1, 0, "s1", NO_CPID, "0 0", _("^K3You were revived by ^BG%s"), "") \
- MULTITEAM_CENTER(1, CENTER_FREEZETAG_ROUND_WIN_, 4, 0, 0, "", NO_CPID, "0 0", _("^TC^TT^BG team wins the round, all other teams were frozen"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_AUTO_REVIVED, 0, 1, "f1", NO_CPID, "0 0", _("^K3You were automatically revived after %s second(s)"), "") \
+ MULTITEAM_CENTER(1, CENTER_ROUND_TEAM_WIN_, 4, 0, 0, "", CPID_ROUND, "0 0", _("^TC^TT^BG team wins the round"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_ROUND_PLAYER_WIN, 1, 0, "s1", CPID_ROUND, "0 0", _("^BG%s^BG wins the round"), "") \
MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_SELF, 0, 0, "", NO_CPID, "0 0", _("^K1You froze yourself"), "") \
- MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_SPAWN_LATE, 0, 0, "", NO_CPID, "0 0", _("^K1You spawned after the round started, you'll spawn as frozen"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_SPAWN_LATE, 0, 0, "", NO_CPID, "0 0", _("^K1Round already started, you spawn as frozen"), "") \
MSG_CENTER_NOTIF(1, CENTER_ITEM_WEAPON_DONTHAVE, 0, 1, "item_wepname", CPID_ITEM, "item_centime 0", _("^BGYou do not have the ^F1%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_ITEM_WEAPON_DROP, 1, 1, "item_wepname item_wepammo", CPID_ITEM, "item_centime 0", _("^BGYou dropped the ^F1%s^BG%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_ITEM_WEAPON_GOT, 0, 1, "item_wepname", CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_HELP, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGAll keys are in your team's hands!\nHelp the key carriers to meet!"), "") \
MULTITEAM_CENTER(1, CENTER_KEYHUNT_INTERFERE_, 4, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGAll keys are in ^TC^TT team^BG's hands!\nInterfere ^F4NOW^BG!"), "") \
MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_MEET, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGAll keys are in your team's hands!\nMeet the other key carriers ^F4NOW^BG!"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_ROUNDSTART, 0, 1, "", CPID_KEYHUNT_OTHER, "1 f1", _("^F4Round will start in ^COUNT"), "") \
MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_SCAN, 0, 1, "", CPID_KEYHUNT_OTHER, "f1 0", _("^BGScanning frequency range..."), "") \
MULTITEAM_CENTER(1, CENTER_KEYHUNT_START_, 4, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGYou are starting with the ^TC^TT Key"), "") \
- MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_WAIT, 0, 4, "kh_teams", CPID_KEYHUNT_OTHER, "0 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_WAIT, 0, 4, "missing_teams", CPID_KEYHUNT_OTHER, "0 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_MISSING_TEAMS, 0, 4, "missing_teams", CPID_MISSING_TEAMS, "-1 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_MISSING_PLAYERS, 0, 1, "f1", CPID_MISSING_PLAYERS, "-1 0", _("^BGWaiting for %s player(s) to join..."), "") \
MSG_CENTER_NOTIF(1, CENTER_LMS_CAMPCHECK, 0, 0, "", CPID_LMS_CAMP, "0 0", _("^F2Don't camp!"), "") \
MSG_CENTER_NOTIF(1, CENTER_MINSTA_FINDAMMO, 0, 0, "", CPID_MINSTA_FINDAMMO, "1 9", _("^F4^COUNT^BG left to find some ammo!"), "") \
MSG_CENTER_NOTIF(1, CENTER_MINSTA_FINDAMMO_FIRST, 0, 0, "", CPID_MINSTA_FINDAMMO, "1 10", _("^BGGet some ammo or you'll be dead in ^F4^COUNT^BG!"), _("^BGGet some ammo! ^F4^COUNT^BG left!")) \
MSG_CENTER_NOTIF(1, CENTER_NIX_COUNTDOWN, 0, 2, "item_wepname", CPID_NIX, "1 f2", _("^F2^COUNT^BG until weapon change...\nNext weapon: ^F1%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_NIX_NEWWEAPON, 0, 1, "item_wepname", CPID_NIX, "0 0", _("^F2Active weapon: ^F1%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_OVERTIME_FRAG, 0, 0, "", CPID_OVERTIME, "0 0", _("^F2Now playing ^F4OVERTIME^F2!\nKeep fragging until we have a winner!"), _("^F2Now playing ^F4OVERTIME^F2!\nKeep scoring until we have a winner!")) \
- MSG_CENTER_NOTIF(1, CENTER_OVERTIME_TIME, 0, 1, "f1time", CPID_OVERTIME, "0 0", _("^F2Now playing ^F4OVERTIME^F2!\nAdded ^F4%s^F2 to the game!"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_OVERTIME_TIME, 0, 1, "f1time", CPID_OVERTIME, "0 0", _("^F2Now playing ^F4OVERTIME^F2!\n^BGAdded ^F4%s^BG to the game!"), "") \
MSG_CENTER_NOTIF(1, CENTER_POWERDOWN_INVISIBILITY, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Invisibility has worn off"), "") \
MSG_CENTER_NOTIF(1, CENTER_POWERDOWN_SHIELD, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Shield has worn off"), "") \
MSG_CENTER_NOTIF(1, CENTER_POWERDOWN_SPEED, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Speed has worn off"), "") \
MSG_CENTER_NOTIF(1, CENTER_TIMEOUT_ENDING, 0, 1, "", CPID_TIMEOUT, "1 f1", _("^F4Timeout ends in ^COUNT"), "")
#define MSG_MULTI_NOTIFICATIONS \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_CHEAT, INFO_DEATH_MURDER_CHEAT, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_DROWN, INFO_DEATH_MURDER_DROWN, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_FALL, INFO_DEATH_MURDER_FALL, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_FIRE, INFO_DEATH_MURDER_FIRE, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_LAVA, INFO_DEATH_MURDER_LAVA, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_SHOOTING_STAR, INFO_DEATH_MURDER_SHOOTING_STAR, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_SLIME, INFO_DEATH_MURDER_SLIME, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_SWAMP, INFO_DEATH_MURDER_SWAMP, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_TELEFRAG, INFO_DEATH_MURDER_TELEFRAG, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_TOUCHEXPLODE, INFO_DEATH_MURDER_TOUCHEXPLODE, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_BUMB_DEATH, INFO_DEATH_MURDER_VH_BUMB_DEATH, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_BUMB_GUN, INFO_DEATH_MURDER_VH_BUMB_GUN, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_CRUSH, INFO_DEATH_MURDER_VH_CRUSH, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_RAPT_BOMB, INFO_DEATH_MURDER_VH_RAPT_BOMB, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_RAPT_CANNON, INFO_DEATH_MURDER_VH_RAPT_CANNON, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_RAPT_DEATH, INFO_DEATH_MURDER_VH_RAPT_DEATH, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_SPID_DEATH, INFO_DEATH_MURDER_VH_SPID_DEATH, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_SPID_MINIGUN, INFO_DEATH_MURDER_VH_SPID_MINIGUN, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_SPID_ROCKET, INFO_DEATH_MURDER_VH_SPID_ROCKET, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_DEATH, INFO_DEATH_MURDER_VH_WAKI_DEATH, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_GUN, INFO_DEATH_MURDER_VH_WAKI_GUN, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_ROCKET, INFO_DEATH_MURDER_VH_WAKI_ROCKET, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_MURDER_VOID, INFO_DEATH_MURDER_VOID, NO_MSG) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_AUTOTEAMCHANGE, INFO_DEATH_SELF_AUTOTEAMCHANGE, CENTER_DEATH_SELF_AUTOTEAMCHANGE) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_BETRAYAL, INFO_DEATH_SELF_BETRAYAL, CENTER_DEATH_SELF_BETRAYAL) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_CAMP, INFO_DEATH_SELF_CAMP, CENTER_DEATH_SELF_CAMP) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_CHEAT, INFO_DEATH_SELF_CHEAT, CENTER_DEATH_SELF_CHEAT) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_CUSTOM, INFO_DEATH_SELF_GENERIC, CENTER_DEATH_SELF_CUSTOM) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_DROWN, INFO_DEATH_SELF_DROWN, CENTER_DEATH_SELF_DROWN) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_FALL, INFO_DEATH_SELF_FALL, CENTER_DEATH_SELF_FALL) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_FIRE, INFO_DEATH_SELF_FIRE, CENTER_DEATH_SELF_FIRE) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_GENERIC, INFO_DEATH_SELF_GENERIC, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_LAVA, INFO_DEATH_SELF_LAVA, CENTER_DEATH_SELF_LAVA) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_NOAMMO, INFO_DEATH_SELF_NOAMMO, CENTER_DEATH_SELF_NOAMMO) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_ROT, INFO_DEATH_SELF_ROT, CENTER_DEATH_SELF_ROT) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_SHOOTING_STAR, INFO_DEATH_SELF_SHOOTING_STAR, CENTER_DEATH_SELF_SHOOTING_STAR) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_SLIME, INFO_DEATH_SELF_SLIME, CENTER_DEATH_SELF_SLIME) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_SUICIDE, INFO_DEATH_SELF_SUICIDE, CENTER_DEATH_SELF_SUICIDE) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_SWAMP, INFO_DEATH_SELF_SWAMP, CENTER_DEATH_SELF_SWAMP) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TEAMCHANGE, INFO_DEATH_SELF_TEAMCHANGE, CENTER_DEATH_SELF_TEAMCHANGE) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TOUCHEXPLODE, INFO_DEATH_SELF_TOUCHEXPLODE, CENTER_DEATH_SELF_TOUCHEXPLODE) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET, INFO_DEATH_SELF_TURRET, CENTER_DEATH_SELF_TURRET) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_EWHEEL, INFO_DEATH_SELF_TURRET_EWHEEL, CENTER_DEATH_SELF_TURRET_EWHEEL) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_FLAC, INFO_DEATH_SELF_TURRET_FLAC, CENTER_DEATH_SELF_TURRET) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_HELLION, INFO_DEATH_SELF_TURRET_HELLION, CENTER_DEATH_SELF_TURRET) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_HK, INFO_DEATH_SELF_TURRET_HK, CENTER_DEATH_SELF_TURRET) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_MACHINEGUN, INFO_DEATH_SELF_TURRET_MACHINEGUN, CENTER_DEATH_SELF_TURRET) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_MLRS, INFO_DEATH_SELF_TURRET_MLRS, CENTER_DEATH_SELF_TURRET) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_PHASER, INFO_DEATH_SELF_TURRET_PHASER, CENTER_DEATH_SELF_TURRET) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_PLASMA, INFO_DEATH_SELF_TURRET_PLASMA, CENTER_DEATH_SELF_TURRET) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_TESLA, INFO_DEATH_SELF_TURRET_TESLA, CENTER_DEATH_SELF_TURRET) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_WALK_GUN, INFO_DEATH_SELF_TURRET_WALK_GUN, CENTER_DEATH_SELF_TURRET_WALK) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_WALK_MEELE, INFO_DEATH_SELF_TURRET_WALK_MEELE, CENTER_DEATH_SELF_TURRET_WALK) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_WALK_ROCKET, INFO_DEATH_SELF_TURRET_WALK_ROCKET, CENTER_DEATH_SELF_TURRET_WALK) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_VH_BUMB_DEATH, INFO_DEATH_SELF_VH_BUMB_DEATH, CENTER_DEATH_SELF_VH_BUMB_DEATH) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_VH_CRUSH, INFO_DEATH_SELF_VH_CRUSH, CENTER_DEATH_SELF_VH_CRUSH) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_VH_RAPT_BOMB, INFO_DEATH_SELF_VH_RAPT_BOMB, CENTER_DEATH_SELF_VH_RAPT_BOMB) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_VH_RAPT_DEATH, INFO_DEATH_SELF_VH_RAPT_DEATH, CENTER_DEATH_SELF_VH_RAPT_DEATH) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_VH_SPID_DEATH, INFO_DEATH_SELF_VH_SPID_DEATH, CENTER_DEATH_SELF_VH_SPID_DEATH) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_VH_SPID_ROCKET, INFO_DEATH_SELF_VH_SPID_ROCKET, CENTER_DEATH_SELF_VH_SPID_ROCKET) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_VH_WAKI_DEATH, INFO_DEATH_SELF_VH_WAKI_DEATH, CENTER_DEATH_SELF_VH_WAKI_DEATH) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_VH_WAKI_ROCKET, INFO_DEATH_SELF_VH_WAKI_ROCKET, CENTER_DEATH_SELF_VH_WAKI_ROCKET) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_VOID, INFO_DEATH_SELF_VOID, CENTER_DEATH_SELF_VOID) \
- MSG_MULTI_NOTIF(1, ITEM_WEAPON_DONTHAVE, INFO_ITEM_WEAPON_DONTHAVE, CENTER_ITEM_WEAPON_DONTHAVE) \
- MSG_MULTI_NOTIF(1, ITEM_WEAPON_DROP, INFO_ITEM_WEAPON_DROP, CENTER_ITEM_WEAPON_DROP) \
- MSG_MULTI_NOTIF(1, ITEM_WEAPON_GOT, INFO_ITEM_WEAPON_GOT, CENTER_ITEM_WEAPON_GOT) \
- MSG_MULTI_NOTIF(1, ITEM_WEAPON_NOAMMO, INFO_ITEM_WEAPON_NOAMMO, CENTER_ITEM_WEAPON_NOAMMO) \
- MSG_MULTI_NOTIF(1, ITEM_WEAPON_PRIMORSEC, INFO_ITEM_WEAPON_PRIMORSEC, CENTER_ITEM_WEAPON_PRIMORSEC) \
- MSG_MULTI_NOTIF(1, ITEM_WEAPON_UNAVAILABLE, INFO_ITEM_WEAPON_UNAVAILABLE, CENTER_ITEM_WEAPON_UNAVAILABLE) \
- MSG_MULTI_NOTIF(1, WEAPON_ACCORDEON_MURDER, INFO_WEAPON_ACCORDEON_MURDER, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_ACCORDEON_SUICIDE, INFO_WEAPON_ACCORDEON_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_CRYLINK_MURDER, INFO_WEAPON_CRYLINK_MURDER, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_CRYLINK_SUICIDE, INFO_WEAPON_CRYLINK_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_ELECTRO_MURDER_BOLT, INFO_WEAPON_ELECTRO_MURDER_BOLT, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_ELECTRO_MURDER_COMBO, INFO_WEAPON_ELECTRO_MURDER_COMBO, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_ELECTRO_MURDER_ORBS, INFO_WEAPON_ELECTRO_MURDER_ORBS, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_ELECTRO_SUICIDE_BOLT, INFO_WEAPON_ELECTRO_SUICIDE_BOLT, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_ELECTRO_SUICIDE_ORBS, INFO_WEAPON_ELECTRO_SUICIDE_ORBS, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_FIREBALL_MURDER_BLAST, INFO_WEAPON_FIREBALL_MURDER_BLAST, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_FIREBALL_MURDER_FIREMINE, INFO_WEAPON_FIREBALL_MURDER_FIREMINE, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_FIREBALL_SUICIDE_BLAST, INFO_WEAPON_FIREBALL_SUICIDE_BLAST, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_FIREBALL_SUICIDE_FIREMINE, INFO_WEAPON_FIREBALL_SUICIDE_FIREMINE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_HAGAR_MURDER_BURST, INFO_WEAPON_HAGAR_MURDER_BURST, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_HAGAR_MURDER_SPRAY, INFO_WEAPON_HAGAR_MURDER_SPRAY, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_HAGAR_SUICIDE, INFO_WEAPON_HAGAR_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_HLAC_MURDER, INFO_WEAPON_HLAC_MURDER, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_HLAC_SUICIDE, INFO_WEAPON_HLAC_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_HOOK_MURDER, INFO_WEAPON_HOOK_MURDER, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_KLEINBOTTLE_MURDER, INFO_WEAPON_KLEINBOTTLE_MURDER, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_KLEINBOTTLE_SUICIDE, INFO_WEAPON_KLEINBOTTLE_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_LASER_MURDER, INFO_WEAPON_LASER_MURDER, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_LASER_SUICIDE, INFO_WEAPON_LASER_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_MINELAYER_MURDER, INFO_WEAPON_MINELAYER_MURDER, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_MINELAYER_SUICIDE, INFO_WEAPON_MINELAYER_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_MINSTANEX_MURDER, INFO_WEAPON_MINSTANEX_MURDER, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_MORTAR_MURDER_BOUNCE, INFO_WEAPON_MORTAR_MURDER_BOUNCE, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_MORTAR_MURDER_EXPLODE, INFO_WEAPON_MORTAR_MURDER_EXPLODE, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_MORTAR_SUICIDE_BOUNCE, INFO_WEAPON_MORTAR_SUICIDE_BOUNCE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_MORTAR_SUICIDE_EXPLODE, INFO_WEAPON_MORTAR_SUICIDE_EXPLODE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_NEX_MURDER, INFO_WEAPON_NEX_MURDER, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_RIFLE_MURDER, INFO_WEAPON_RIFLE_MURDER, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_RIFLE_MURDER_HAIL, INFO_WEAPON_RIFLE_MURDER_HAIL, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_RIFLE_MURDER_HAIL_PIERCING, INFO_WEAPON_RIFLE_MURDER_HAIL_PIERCING, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_RIFLE_MURDER_HEADSHOT, INFO_WEAPON_RIFLE_MURDER_HEADSHOT, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_RIFLE_MURDER_PIERCING, INFO_WEAPON_RIFLE_MURDER_PIERCING, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_ROCKETLAUNCHER_MURDER_DIRECT, INFO_WEAPON_ROCKETLAUNCHER_MURDER_DIRECT, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_ROCKETLAUNCHER_MURDER_SPLASH, INFO_WEAPON_ROCKETLAUNCHER_MURDER_SPLASH, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_ROCKETLAUNCHER_SUICIDE, INFO_WEAPON_ROCKETLAUNCHER_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_SEEKER_MURDER_SPRAY, INFO_WEAPON_SEEKER_MURDER_SPRAY, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_SEEKER_MURDER_TAG, INFO_WEAPON_SEEKER_MURDER_TAG, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_SEEKER_SUICIDE, INFO_WEAPON_SEEKER_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_SHOTGUN_MURDER, INFO_WEAPON_SHOTGUN_MURDER, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_SHOTGUN_MURDER_SLAP, INFO_WEAPON_SHOTGUN_MURDER_SLAP, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_THINKING_WITH_PORTALS, INFO_WEAPON_THINKING_WITH_PORTALS, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_TUBA_MURDER, INFO_WEAPON_TUBA_MURDER, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_TUBA_SUICIDE, INFO_WEAPON_TUBA_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_UZI_MURDER_SNIPE, INFO_WEAPON_UZI_MURDER_SNIPE, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_UZI_MURDER_SPRAY, INFO_WEAPON_UZI_MURDER_SPRAY, NO_MSG)
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_CHEAT, NO_MSG, INFO_DEATH_MURDER_CHEAT, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_DROWN, NO_MSG, INFO_DEATH_MURDER_DROWN, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_FALL, NO_MSG, INFO_DEATH_MURDER_FALL, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_FIRE, NO_MSG, INFO_DEATH_MURDER_FIRE, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_LAVA, NO_MSG, INFO_DEATH_MURDER_LAVA, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_SHOOTING_STAR, NO_MSG, INFO_DEATH_MURDER_SHOOTING_STAR, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_SLIME, NO_MSG, INFO_DEATH_MURDER_SLIME, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_SWAMP, NO_MSG, INFO_DEATH_MURDER_SWAMP, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_TELEFRAG, NO_MSG, INFO_DEATH_MURDER_TELEFRAG, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_TOUCHEXPLODE, NO_MSG, INFO_DEATH_MURDER_TOUCHEXPLODE, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_BUMB_DEATH, NO_MSG, INFO_DEATH_MURDER_VH_BUMB_DEATH, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_BUMB_GUN, NO_MSG, INFO_DEATH_MURDER_VH_BUMB_GUN, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_CRUSH, NO_MSG, INFO_DEATH_MURDER_VH_CRUSH, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_RAPT_BOMB, NO_MSG, INFO_DEATH_MURDER_VH_RAPT_BOMB, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_RAPT_CANNON, NO_MSG, INFO_DEATH_MURDER_VH_RAPT_CANNON, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_RAPT_DEATH, NO_MSG, INFO_DEATH_MURDER_VH_RAPT_DEATH, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_SPID_DEATH, NO_MSG, INFO_DEATH_MURDER_VH_SPID_DEATH, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_SPID_MINIGUN, NO_MSG, INFO_DEATH_MURDER_VH_SPID_MINIGUN, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_SPID_ROCKET, NO_MSG, INFO_DEATH_MURDER_VH_SPID_ROCKET, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_DEATH, NO_MSG, INFO_DEATH_MURDER_VH_WAKI_DEATH, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_GUN, NO_MSG, INFO_DEATH_MURDER_VH_WAKI_GUN, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_ROCKET, NO_MSG, INFO_DEATH_MURDER_VH_WAKI_ROCKET, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_MURDER_VOID, NO_MSG, INFO_DEATH_MURDER_VOID, NO_MSG) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_AUTOTEAMCHANGE, NO_MSG, INFO_DEATH_SELF_AUTOTEAMCHANGE, CENTER_DEATH_SELF_AUTOTEAMCHANGE) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_BETRAYAL, NO_MSG, INFO_DEATH_SELF_BETRAYAL, CENTER_DEATH_SELF_BETRAYAL) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_CAMP, NO_MSG, INFO_DEATH_SELF_CAMP, CENTER_DEATH_SELF_CAMP) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_CHEAT, NO_MSG, INFO_DEATH_SELF_CHEAT, CENTER_DEATH_SELF_CHEAT) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_CUSTOM, NO_MSG, INFO_DEATH_SELF_GENERIC, CENTER_DEATH_SELF_CUSTOM) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_DROWN, NO_MSG, INFO_DEATH_SELF_DROWN, CENTER_DEATH_SELF_DROWN) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_FALL, NO_MSG, INFO_DEATH_SELF_FALL, CENTER_DEATH_SELF_FALL) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_FIRE, NO_MSG, INFO_DEATH_SELF_FIRE, CENTER_DEATH_SELF_FIRE) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_GENERIC, NO_MSG, INFO_DEATH_SELF_GENERIC, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_LAVA, NO_MSG, INFO_DEATH_SELF_LAVA, CENTER_DEATH_SELF_LAVA) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_NOAMMO, NO_MSG, INFO_DEATH_SELF_NOAMMO, CENTER_DEATH_SELF_NOAMMO) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_ROT, NO_MSG, INFO_DEATH_SELF_ROT, CENTER_DEATH_SELF_ROT) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_SHOOTING_STAR, NO_MSG, INFO_DEATH_SELF_SHOOTING_STAR, CENTER_DEATH_SELF_SHOOTING_STAR) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_SLIME, NO_MSG, INFO_DEATH_SELF_SLIME, CENTER_DEATH_SELF_SLIME) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_SUICIDE, NO_MSG, INFO_DEATH_SELF_SUICIDE, CENTER_DEATH_SELF_SUICIDE) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_SWAMP, NO_MSG, INFO_DEATH_SELF_SWAMP, CENTER_DEATH_SELF_SWAMP) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TEAMCHANGE, NO_MSG, INFO_DEATH_SELF_TEAMCHANGE, CENTER_DEATH_SELF_TEAMCHANGE) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TOUCHEXPLODE, NO_MSG, INFO_DEATH_SELF_TOUCHEXPLODE, CENTER_DEATH_SELF_TOUCHEXPLODE) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET, NO_MSG, INFO_DEATH_SELF_TURRET, CENTER_DEATH_SELF_TURRET) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_EWHEEL, NO_MSG, INFO_DEATH_SELF_TURRET_EWHEEL, CENTER_DEATH_SELF_TURRET_EWHEEL) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_FLAC, NO_MSG, INFO_DEATH_SELF_TURRET_FLAC, CENTER_DEATH_SELF_TURRET) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_HELLION, NO_MSG, INFO_DEATH_SELF_TURRET_HELLION, CENTER_DEATH_SELF_TURRET) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_HK, NO_MSG, INFO_DEATH_SELF_TURRET_HK, CENTER_DEATH_SELF_TURRET) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_MACHINEGUN, NO_MSG, INFO_DEATH_SELF_TURRET_MACHINEGUN, CENTER_DEATH_SELF_TURRET) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_MLRS, NO_MSG, INFO_DEATH_SELF_TURRET_MLRS, CENTER_DEATH_SELF_TURRET) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_PHASER, NO_MSG, INFO_DEATH_SELF_TURRET_PHASER, CENTER_DEATH_SELF_TURRET) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_PLASMA, NO_MSG, INFO_DEATH_SELF_TURRET_PLASMA, CENTER_DEATH_SELF_TURRET) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_TESLA, NO_MSG, INFO_DEATH_SELF_TURRET_TESLA, CENTER_DEATH_SELF_TURRET) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_WALK_GUN, NO_MSG, INFO_DEATH_SELF_TURRET_WALK_GUN, CENTER_DEATH_SELF_TURRET_WALK) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_WALK_MEELE, NO_MSG, INFO_DEATH_SELF_TURRET_WALK_MEELE, CENTER_DEATH_SELF_TURRET_WALK) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_WALK_ROCKET, NO_MSG, INFO_DEATH_SELF_TURRET_WALK_ROCKET, CENTER_DEATH_SELF_TURRET_WALK) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_VH_BUMB_DEATH, NO_MSG, INFO_DEATH_SELF_VH_BUMB_DEATH, CENTER_DEATH_SELF_VH_BUMB_DEATH) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_VH_CRUSH, NO_MSG, INFO_DEATH_SELF_VH_CRUSH, CENTER_DEATH_SELF_VH_CRUSH) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_VH_RAPT_BOMB, NO_MSG, INFO_DEATH_SELF_VH_RAPT_BOMB, CENTER_DEATH_SELF_VH_RAPT_BOMB) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_VH_RAPT_DEATH, NO_MSG, INFO_DEATH_SELF_VH_RAPT_DEATH, CENTER_DEATH_SELF_VH_RAPT_DEATH) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_VH_SPID_DEATH, NO_MSG, INFO_DEATH_SELF_VH_SPID_DEATH, CENTER_DEATH_SELF_VH_SPID_DEATH) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_VH_SPID_ROCKET, NO_MSG, INFO_DEATH_SELF_VH_SPID_ROCKET, CENTER_DEATH_SELF_VH_SPID_ROCKET) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_VH_WAKI_DEATH, NO_MSG, INFO_DEATH_SELF_VH_WAKI_DEATH, CENTER_DEATH_SELF_VH_WAKI_DEATH) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_VH_WAKI_ROCKET, NO_MSG, INFO_DEATH_SELF_VH_WAKI_ROCKET, CENTER_DEATH_SELF_VH_WAKI_ROCKET) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_VOID, NO_MSG, INFO_DEATH_SELF_VOID, CENTER_DEATH_SELF_VOID) \
+ MSG_MULTI_NOTIF(1, ITEM_WEAPON_DONTHAVE, NO_MSG, INFO_ITEM_WEAPON_DONTHAVE, CENTER_ITEM_WEAPON_DONTHAVE) \
+ MSG_MULTI_NOTIF(1, ITEM_WEAPON_DROP, NO_MSG, INFO_ITEM_WEAPON_DROP, CENTER_ITEM_WEAPON_DROP) \
+ MSG_MULTI_NOTIF(1, ITEM_WEAPON_GOT, NO_MSG, INFO_ITEM_WEAPON_GOT, CENTER_ITEM_WEAPON_GOT) \
+ MSG_MULTI_NOTIF(1, ITEM_WEAPON_NOAMMO, NO_MSG, INFO_ITEM_WEAPON_NOAMMO, CENTER_ITEM_WEAPON_NOAMMO) \
+ MSG_MULTI_NOTIF(1, ITEM_WEAPON_PRIMORSEC, NO_MSG, INFO_ITEM_WEAPON_PRIMORSEC, CENTER_ITEM_WEAPON_PRIMORSEC) \
+ MSG_MULTI_NOTIF(1, ITEM_WEAPON_UNAVAILABLE, NO_MSG, INFO_ITEM_WEAPON_UNAVAILABLE, CENTER_ITEM_WEAPON_UNAVAILABLE) \
+ MSG_MULTI_NOTIF(1, MULTI_COUNTDOWN_BEGIN, ANNCE_BEGIN, NO_MSG, CENTER_COUNTDOWN_BEGIN) \
+ MSG_MULTI_NOTIF(1, MULTI_MINSTA_FINDAMMO, ANNCE_NUM_10, NO_MSG, CENTER_MINSTA_FINDAMMO_FIRST) \
+ MSG_MULTI_NOTIF(1, WEAPON_ACCORDEON_MURDER, NO_MSG, INFO_WEAPON_ACCORDEON_MURDER, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_ACCORDEON_SUICIDE, NO_MSG, INFO_WEAPON_ACCORDEON_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_CRYLINK_MURDER, NO_MSG, INFO_WEAPON_CRYLINK_MURDER, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_CRYLINK_SUICIDE, NO_MSG, INFO_WEAPON_CRYLINK_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_ELECTRO_MURDER_BOLT, NO_MSG, INFO_WEAPON_ELECTRO_MURDER_BOLT, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_ELECTRO_MURDER_COMBO, NO_MSG, INFO_WEAPON_ELECTRO_MURDER_COMBO, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_ELECTRO_MURDER_ORBS, NO_MSG, INFO_WEAPON_ELECTRO_MURDER_ORBS, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_ELECTRO_SUICIDE_BOLT, NO_MSG, INFO_WEAPON_ELECTRO_SUICIDE_BOLT, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_ELECTRO_SUICIDE_ORBS, NO_MSG, INFO_WEAPON_ELECTRO_SUICIDE_ORBS, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_FIREBALL_MURDER_BLAST, NO_MSG, INFO_WEAPON_FIREBALL_MURDER_BLAST, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_FIREBALL_MURDER_FIREMINE, NO_MSG, INFO_WEAPON_FIREBALL_MURDER_FIREMINE, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_FIREBALL_SUICIDE_BLAST, NO_MSG, INFO_WEAPON_FIREBALL_SUICIDE_BLAST, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_FIREBALL_SUICIDE_FIREMINE, NO_MSG, INFO_WEAPON_FIREBALL_SUICIDE_FIREMINE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_HAGAR_MURDER_BURST, NO_MSG, INFO_WEAPON_HAGAR_MURDER_BURST, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_HAGAR_MURDER_SPRAY, NO_MSG, INFO_WEAPON_HAGAR_MURDER_SPRAY, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_HAGAR_SUICIDE, NO_MSG, INFO_WEAPON_HAGAR_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_HLAC_MURDER, NO_MSG, INFO_WEAPON_HLAC_MURDER, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_HLAC_SUICIDE, NO_MSG, INFO_WEAPON_HLAC_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_HOOK_MURDER, NO_MSG, INFO_WEAPON_HOOK_MURDER, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_KLEINBOTTLE_MURDER, NO_MSG, INFO_WEAPON_KLEINBOTTLE_MURDER, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_KLEINBOTTLE_SUICIDE, NO_MSG, INFO_WEAPON_KLEINBOTTLE_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_LASER_MURDER, NO_MSG, INFO_WEAPON_LASER_MURDER, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_LASER_SUICIDE, NO_MSG, INFO_WEAPON_LASER_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_MINELAYER_MURDER, NO_MSG, INFO_WEAPON_MINELAYER_MURDER, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_MINELAYER_SUICIDE, NO_MSG, INFO_WEAPON_MINELAYER_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_MINSTANEX_MURDER, NO_MSG, INFO_WEAPON_MINSTANEX_MURDER, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_MORTAR_MURDER_BOUNCE, NO_MSG, INFO_WEAPON_MORTAR_MURDER_BOUNCE, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_MORTAR_MURDER_EXPLODE, NO_MSG, INFO_WEAPON_MORTAR_MURDER_EXPLODE, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_MORTAR_SUICIDE_BOUNCE, NO_MSG, INFO_WEAPON_MORTAR_SUICIDE_BOUNCE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_MORTAR_SUICIDE_EXPLODE, NO_MSG, INFO_WEAPON_MORTAR_SUICIDE_EXPLODE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_NEX_MURDER, NO_MSG, INFO_WEAPON_NEX_MURDER, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_RIFLE_MURDER, NO_MSG, INFO_WEAPON_RIFLE_MURDER, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_RIFLE_MURDER_HAIL, NO_MSG, INFO_WEAPON_RIFLE_MURDER_HAIL, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_RIFLE_MURDER_HAIL_PIERCING, NO_MSG, INFO_WEAPON_RIFLE_MURDER_HAIL_PIERCING, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_RIFLE_MURDER_PIERCING, NO_MSG, INFO_WEAPON_RIFLE_MURDER_PIERCING, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_ROCKETLAUNCHER_MURDER_DIRECT, NO_MSG, INFO_WEAPON_ROCKETLAUNCHER_MURDER_DIRECT, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_ROCKETLAUNCHER_MURDER_SPLASH, NO_MSG, INFO_WEAPON_ROCKETLAUNCHER_MURDER_SPLASH, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_ROCKETLAUNCHER_SUICIDE, NO_MSG, INFO_WEAPON_ROCKETLAUNCHER_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_SEEKER_MURDER_SPRAY, NO_MSG, INFO_WEAPON_SEEKER_MURDER_SPRAY, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_SEEKER_MURDER_TAG, NO_MSG, INFO_WEAPON_SEEKER_MURDER_TAG, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_SEEKER_SUICIDE, NO_MSG, INFO_WEAPON_SEEKER_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_SHOTGUN_MURDER, NO_MSG, INFO_WEAPON_SHOTGUN_MURDER, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_SHOTGUN_MURDER_SLAP, NO_MSG, INFO_WEAPON_SHOTGUN_MURDER_SLAP, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_THINKING_WITH_PORTALS, NO_MSG, INFO_WEAPON_THINKING_WITH_PORTALS, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_TUBA_MURDER, NO_MSG, INFO_WEAPON_TUBA_MURDER, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_TUBA_SUICIDE, NO_MSG, INFO_WEAPON_TUBA_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_UZI_MURDER_SNIPE, NO_MSG, INFO_WEAPON_UZI_MURDER_SNIPE, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_UZI_MURDER_SPRAY, NO_MSG, INFO_WEAPON_UZI_MURDER_SPRAY, NO_MSG)
// ===========================
var float autocvar_notification_errors_are_fatal = TRUE;
var float autocvar_notification_lifetime_runtime = 0.5;
var float autocvar_notification_lifetime_mapload = 10;
+var float autocvar_notification_debug = FALSE;
#ifdef SVQC
.float FRAG_VERBOSE;
f2race_time: mmssss of f2
race_col: color of race time/position (i.e. good or bad)
race_diff: show time difference between f2 and f3
- kh_teams: show which teams still need players in keyhunt centerprint
+ missing_teams: show which teams still need players
pass_key: find the keybind for "passing" or "dropping" in CTF game mode
frag_ping: show the ping of a player
frag_stats: show health/armor/ping of a player
ARG_CASE(ARG_CS, "f1time", process_time(2, f1)) \
ARG_CASE(ARG_CS_SV, "f1race_time", mmssss(f1)) \
ARG_CASE(ARG_CS_SV, "f2race_time", mmssss(f2)) \
+ ARG_CASE(ARG_CS_SV, "f3race_time", mmssss(f3)) \
ARG_CASE(ARG_CS_SV, "race_col", CCR(((f1 == 1) ? "^F1" : "^F2"))) \
ARG_CASE(ARG_CS_SV, "race_diff", ((f2 > f3) ? sprintf(CCR("^1[+%s]"), mmssss(f2 - f3)) : sprintf(CCR("^2[-%s]"), mmssss(f3 - f2)))) \
- ARG_CASE(ARG_CS, "kh_teams", notif_arg_kh_teams(f1, f2, f3, f4)) \
+ ARG_CASE(ARG_CS, "missing_teams", notif_arg_missing_teams(f1, f2, f3, f4)) \
ARG_CASE(ARG_CS, "pass_key", ((((tmp_s = getcommandkey("pass", "+use")) != "pass") && !(strstrofs(tmp_s, "not bound", 0) >= 0)) ? sprintf(CCR(_(" ^F1(Press %s)")), tmp_s) : "")) \
ARG_CASE(ARG_CS, "frag_ping", notif_arg_frag_ping(TRUE, f2)) \
ARG_CASE(ARG_CS, "frag_stats", notif_arg_frag_stats(f2, f3, f4)) \
return sprintf(CCR(_("\n(^F4Dead^BG)%s")), notif_arg_frag_ping(FALSE, fping));
}
-string notif_arg_kh_teams(float f1, float f2, float f3, float f4)
+string notif_arg_missing_teams(float f1, float f2, float f3, float f4)
{
return sprintf("%s%s%s%s",
(f1 ?
float notif_global_error;
// notification entities
+entity msg_annce_notifs[NOTIF_MAX];
entity msg_info_notifs[NOTIF_MAX];
entity msg_center_notifs[NOTIF_MAX];
entity msg_multi_notifs[NOTIF_MAX];
// notification counts
+float NOTIF_ANNCE_COUNT;
float NOTIF_INFO_COUNT;
float NOTIF_CENTER_COUNT;
float NOTIF_MULTI_COUNT;
.string nent_name;
.float nent_id;
.float nent_enabled;
+.entity nent_msgannce;
.entity nent_msginfo;
.entity nent_msgcenter;
+.float nent_channel;
+.string nent_snd;
+.float nent_vol;
+.float nent_position;
.float nent_stringcount;
.float nent_floatcount;
.string nent_args;
.string nent_strings[4];
.float nent_floats[4];
+#define MSG_ANNCE_NOTIF(default,name,channel,sound,volume,position) \
+ NOTIF_ADD_AUTOCVAR(name, default) \
+ float name; \
+ void RegisterNotification_##name() \
+ { \
+ SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_ANNCE_COUNT) \
+ CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_ANNCE_COUNT, "notifications") \
+ Create_Notification_Entity( \
+ default, /* var_default */ \
+ autocvar_notification_##name, /* var_cvar */ \
+ MSG_ANNCE, /* typeid */ \
+ name, /* nameid */ \
+ strtoupper(#name), /* namestring */ \
+ NO_MSG, /* anncename */ \
+ NO_MSG, /* infoname */ \
+ NO_MSG, /* centername */ \
+ channel, /* channel */ \
+ sound, /* snd */ \
+ volume, /* vol */ \
+ position, /* position */ \
+ NO_MSG, /* strnum */ \
+ NO_MSG, /* flnum */ \
+ "", /* args */ \
+ "", /* hudargs */ \
+ "", /* icon */ \
+ NO_MSG, /* cpid */ \
+ "", /* durcnt */ \
+ "", /* normal */ \
+ "", /* gentle */ \
+ FALSE, /* msg_is_info */ \
+ FALSE); /* msg_is_multi */ \
+ } \
+ ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
+
#define MSG_INFO_NOTIF(default,name,strnum,flnum,args,hudargs,icon,normal,gentle) \
NOTIF_ADD_AUTOCVAR(name, default) \
float name; \
MSG_INFO, /* typeid */ \
name, /* nameid */ \
strtoupper(#name), /* namestring */ \
+ NO_MSG, /* anncename */ \
NO_MSG, /* infoname */ \
NO_MSG, /* centername */ \
+ NO_MSG, /* channel */ \
+ "", /* snd */ \
+ NO_MSG, /* vol */ \
+ NO_MSG, /* position */ \
strnum, /* strnum */ \
flnum, /* flnum */ \
args, /* args */ \
MSG_CENTER, /* typeid */ \
name, /* nameid */ \
strtoupper(#name), /* namestring */ \
+ NO_MSG, /* anncename */ \
NO_MSG, /* infoname */ \
NO_MSG, /* centername */ \
+ NO_MSG, /* channel */ \
+ "", /* snd */ \
+ NO_MSG, /* vol */ \
+ NO_MSG, /* position */ \
strnum, /* strnum */ \
flnum, /* flnum */ \
args, /* args */ \
} \
ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
-#define MSG_MULTI_NOTIF(default,name,infoname,centername) \
+#define MSG_MULTI_NOTIF(default,name,anncename,infoname,centername) \
NOTIF_ADD_AUTOCVAR(name, default) \
float name; \
void RegisterNotification_##name() \
MSG_MULTI, /* typeid */ \
name, /* nameid */ \
strtoupper(#name), /* namestring */ \
+ anncename, /* anncename */ \
infoname, /* infoname */ \
centername, /* centername */ \
+ NO_MSG, /* channel */ \
+ "", /* snd */ \
+ NO_MSG, /* vol */ \
+ NO_MSG, /* position */ \
NO_MSG, /* strnum */ \
NO_MSG, /* flnum */ \
"", /* args */ \
// NOW we actually activate the declarations
ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotifications_First)
+MSG_ANNCE_NOTIFICATIONS
MSG_INFO_NOTIFICATIONS
MSG_CENTER_NOTIFICATIONS
MSG_MULTI_NOTIFICATIONS
ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotifications_Done)
+#undef MSG_ANNCE_NOTIF
#undef MSG_INFO_NOTIF
#undef MSG_CENTER_NOTIF
#undef MSG_MULTI_NOTIF
const string NAME_TEAM = _("Team");
const string NAME_NEUTRAL = _("Neutral");
+// used for replacement in filenames or such where the name CANNOT be allowed to be translated
+const string STATIC_NAME_TEAM_1 = "Red";
+const string STATIC_NAME_TEAM_2 = "Blue";
+const string STATIC_NAME_TEAM_3 = "Yellow";
+const string STATIC_NAME_TEAM_4 = "Pink";
+
#define APP_TEAM_NUM_2(num,prefix) ((num == NUM_TEAM_1) ? prefix##RED : prefix##BLUE)
#define APP_TEAM_NUM_4(num,prefix) ((num == NUM_TEAM_1) ? prefix##RED : ((num == NUM_TEAM_2) ? prefix##BLUE : ((num == NUM_TEAM_3) ? prefix##YELLOW : prefix##PINK)))
#define APP_TEAM_ENT_2(ent,prefix) ((ent.team == NUM_TEAM_1) ? prefix##RED : prefix##BLUE)
{
switch(teamid)
{
- #ifdef TEAMNUMBERS_THAT_ARENT_STUPID
- case NUM_TEAM_1: return '1 0 0'; // red
- case NUM_TEAM_2: return '0 0 1'; // blue
- case NUM_TEAM_3: return '1 1 0'; // yellow
- case NUM_TEAM_4: return '1 0 1'; // pink
- #else
case NUM_TEAM_1: return '1 0.0625 0.0625';
case NUM_TEAM_2: return '0.0625 0.0625 1';
case NUM_TEAM_3: return '1 1 0.0625';
case NUM_TEAM_4: return '1 0.0625 1';
- #endif
}
return '0 0 0';
return NAME_NEUTRAL;
}
+// used for replacement in filenames or such where the name CANNOT be allowed to be translated
+string Static_Team_ColorName(float teamid)
+{
+ switch(teamid)
+ {
+ case NUM_TEAM_1: return STATIC_NAME_TEAM_1;
+ case NUM_TEAM_2: return STATIC_NAME_TEAM_2;
+ case NUM_TEAM_3: return STATIC_NAME_TEAM_3;
+ case NUM_TEAM_4: return STATIC_NAME_TEAM_4;
+ }
+
+ return NAME_NEUTRAL;
+}
+
float Team_ColorToTeam(string team_color)
{
switch(strtolower(team_color))
#define Team_ColorName_Lower(teamid) strtolower(Team_ColorName(teamid))
#define Team_ColorName_Upper(teamid) strtoupper(Team_ColorName(teamid))
+// used for replacement in filenames or such where the name CANNOT be allowed to be translated
+#define Static_Team_ColorName_Lower(teamid) strtolower(Static_Team_ColorName(teamid))
+#define Static_Team_ColorName_Upper(teamid) strtoupper(Static_Team_ColorName(teamid))
+
#define Team_FullName(teamid) strcat(Team_ColorName(teamid), " ", NAME_TEAM, "^7")
#define Team_ColoredFullName(teamid) strcat(Team_ColorCode(teamid), Team_ColorName(teamid), " ", NAME_TEAM, "^7")
#ifndef NOCOMPAT
//# define WORKAROUND_XON010
//# define COMPAT_XON010_CHANNELS
-# define COMPAT_XON050_ENGINE
+//# define COMPAT_XON050_ENGINE
# define COMPAT_NO_MOD_IS_XONOTIC
# define COMPAT_XON060_DONTCRASH_CHECKPVS
#endif
if(server_is_dedicated) { print(input); }
}
#endif
+
+#ifndef MENUQC
+float Announcer_PickNumber(float num)
+{
+ switch(num)
+ {
+ case 10: num = ANNCE_NUM_10; break;
+ case 9: num = ANNCE_NUM_9; break;
+ case 8: num = ANNCE_NUM_8; break;
+ case 7: num = ANNCE_NUM_7; break;
+ case 6: num = ANNCE_NUM_6; break;
+ case 5: num = ANNCE_NUM_5; break;
+ case 4: num = ANNCE_NUM_4; break;
+ case 3: num = ANNCE_NUM_3; break;
+ case 2: num = ANNCE_NUM_2; break;
+ case 1: num = ANNCE_NUM_1; break;
+ }
+ return num;
+}
+#endif
string get_model_parameters_desc;
float get_model_parameters(string mod, float skn); // call with string_null to clear; skin -1 means mod is the filename of the txt file and is to be split
-// stupid stupid stupid FTEQCC has a max limit on macro sizes, let's work around by splitting the macro into two macros! :(
-#define HUD_Panel_GetName_Part2(id) \
-switch(id) {\
- case HUD_PANEL_ENGINEINFO: panel_name = HUD_PANELNAME_ENGINEINFO; break; \
- case HUD_PANEL_INFOMESSAGES: panel_name = HUD_PANELNAME_INFOMESSAGES; break; \
- case HUD_PANEL_PHYSICS: panel_name = HUD_PANELNAME_PHYSICS; break; \
- case HUD_PANEL_CENTERPRINT: panel_name = HUD_PANELNAME_CENTERPRINT; break; \
-} ENDS_WITH_CURLY_BRACE
-
-// Get name of specified panel id
-#define HUD_Panel_GetName(id) \
-switch(id) { \
- case HUD_PANEL_WEAPONS: panel_name = HUD_PANELNAME_WEAPONS; break; \
- case HUD_PANEL_AMMO: panel_name = HUD_PANELNAME_AMMO; break; \
- case HUD_PANEL_POWERUPS: panel_name = HUD_PANELNAME_POWERUPS; break; \
- case HUD_PANEL_HEALTHARMOR: panel_name = HUD_PANELNAME_HEALTHARMOR; break; \
- case HUD_PANEL_NOTIFY: panel_name = HUD_PANELNAME_NOTIFY; break; \
- case HUD_PANEL_TIMER: panel_name = HUD_PANELNAME_TIMER; break; \
- case HUD_PANEL_RADAR: panel_name = HUD_PANELNAME_RADAR; break; \
- case HUD_PANEL_SCORE: panel_name = HUD_PANELNAME_SCORE; break; \
- case HUD_PANEL_RACETIMER: panel_name = HUD_PANELNAME_RACETIMER; break; \
- case HUD_PANEL_VOTE: panel_name = HUD_PANELNAME_VOTE; break; \
- case HUD_PANEL_MODICONS: panel_name = HUD_PANELNAME_MODICONS; break; \
- case HUD_PANEL_PRESSEDKEYS: panel_name = HUD_PANELNAME_PRESSEDKEYS; break; \
- case HUD_PANEL_CHAT: panel_name = HUD_PANELNAME_CHAT; break; \
- default: HUD_Panel_GetName_Part2(id)\
-}
-
vector vec2(vector v);
#ifndef MENUQC
#define PROGNAME "CSQC"
#endif
#endif
+
+#ifndef MENUQC
+float Announcer_PickNumber(float num);
+#endif
#include "xonotic/slider_resolution.c"
#include "xonotic/checkbox.c"
#include "xonotic/checkbox_string.c"
+#include "xonotic/weaponarenacheckbox.c"
#include "xonotic/radiobutton.c"
#include "xonotic/nexposee.c"
#include "xonotic/rootdialog.c"
METHOD(InputBox, setText, void(entity, string))
METHOD(InputBox, enterText, void(entity, string))
METHOD(InputBox, keyDown, float(entity, float, float, float))
+ METHOD(InputBox, mouseMove, float(entity, vector))
METHOD(InputBox, mouseRelease, float(entity, vector))
METHOD(InputBox, mousePress, float(entity, vector))
METHOD(InputBox, mouseDrag, float(entity, vector))
METHOD(InputBox, showNotify, void(entity))
+ METHOD(InputBox, resizeNotify, void(entity, vector, vector, vector, vector))
ATTRIB(InputBox, src, string, string_null)
ATTRIB(InputBox, color, vector, '1 1 1')
ATTRIB(InputBox, colorF, vector, '1 1 1')
ATTRIB(InputBox, maxLength, float, 255) // if negative, it counts bytes, not chars
+
+ ATTRIB(InputBox, enableClearButton, float, 1)
+ ATTRIB(InputBox, clearButton, entity, NULL)
+ ATTRIB(InputBox, cb_width, float, 0)
+ ATTRIB(InputBox, cb_pressed, float, 0)
+ ATTRIB(InputBox, cb_focused, float, 0)
+ ATTRIB(InputBox, cb_color, vector, '1 1 1')
+ ATTRIB(InputBox, cb_colorF, vector, '1 1 1')
+ ATTRIB(InputBox, cb_colorC, vector, '1 1 1')
ENDCLASS(InputBox)
void InputBox_Clear_Click(entity btn, entity me);
#endif
me.src = gfx;
me.cursorPos = theCursorPos;
}
+void InputBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ SUPER(InputBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+ if (me.enableClearButton)
+ {
+ me.cb_width = absSize_y / absSize_x;
+ me.cb_offset = bound(-1, me.cb_offset, 0) * me.cb_width; // bound to range -1, 0
+ me.keepspaceRight = me.keepspaceRight - me.cb_offset + me.cb_width;
+ }
+}
void InputBox_setText(entity me, string txt)
{
me.setText(me, "");
}
+float over_ClearButton(entity me, vector pos)
+{
+ if (pos_x >= 1 + me.cb_offset - me.cb_width)
+ if (pos_x < 1 + me.cb_offset)
+ if (pos_y >= 0)
+ if (pos_y < 1)
+ return 1;
+ return 0;
+}
+
+float InputBox_mouseMove(entity me, vector pos)
+{
+ if (me.enableClearButton)
+ {
+ if (over_ClearButton(me, pos))
+ {
+ me.cb_focused = 1;
+ return 1;
+ }
+ me.cb_focused = 0;
+ }
+ return 1;
+}
+
float InputBox_mouseDrag(entity me, vector pos)
{
float p;
- me.dragScrollPos = pos;
- p = me.scrollPos + pos_x - me.keepspaceLeft;
- me.cursorPos = draw_TextLengthUpToWidth(me.text, p, 0, me.realFontSize);
- me.lastChangeTime = time;
+ if(me.pressed)
+ {
+ me.dragScrollPos = pos;
+ p = me.scrollPos + pos_x - me.keepspaceLeft;
+ me.cursorPos = draw_TextLengthUpToWidth(me.text, p, 0, me.realFontSize);
+ me.lastChangeTime = time;
+ }
+ else if (me.enableClearButton)
+ {
+ if (over_ClearButton(me, pos))
+ {
+ me.cb_pressed = 1;
+ return 1;
+ }
+ }
+ me.cb_pressed = 0;
return 1;
}
float InputBox_mousePress(entity me, vector pos)
{
+ if (me.enableClearButton)
+ if (over_ClearButton(me, pos))
+ {
+ me.cb_pressed = 1;
+ return 1;
+ }
me.dragScrollTimer = time;
me.pressed = 1;
return InputBox_mouseDrag(me, pos);
float InputBox_mouseRelease(entity me, vector pos)
{
+ if(me.cb_pressed)
+ if (over_ClearButton(me, pos))
+ {
+ me.cb_pressed = 0;
+ InputBox_Clear_Click(world, me);
+ return 1;
+ }
+ float r = InputBox_mouseDrag(me, pos);
+ //reset cb_pressed after mouseDrag, mouseDrag could set cb_pressed in this case:
+ //mouse press out of the clear button, drag and then mouse release over the clear button
+ me.cb_pressed = 0;
me.pressed = 0;
- return InputBox_mouseDrag(me, pos);
+ return r;
}
void InputBox_enterText(entity me, string ch)
draw_ClearClip();
+ if (me.enableClearButton)
+ if (me.text != "")
+ {
+ if(me.focused && me.cb_pressed)
+ draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_c"), eX * me.cb_width + eY, me.cb_colorC, 1);
+ else if(me.focused && me.cb_focused)
+ draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_f"), eX * me.cb_width + eY, me.cb_colorF, 1);
+ else
+ draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_n"), eX * me.cb_width + eY, me.cb_color, 1);
+ }
+
// skipping SUPER(InputBox).draw(me);
Item_draw(me);
}
}
float InputContainer_mouseMove(entity me, vector pos)
{
+ if(me.mouseFocusedChild != me.focusedChild) // if the keyboard moved the focus away
+ me.mouseFocusedChild = NULL; // force focusing
if(me._changeFocusXY(me, pos))
if(SUPER(InputContainer).mouseMove(me, pos))
return 1;
if(me.animationState == 0)
{
if(me.mouseFocusedChild)
- if(me.mouseFocusedChild != e)
+ if(me.mouseFocusedChild != e || me.mouseFocusedChild != me.selectedChild)
me.selectedChild = me.mouseFocusedChild;
return 1;
}
if(Menu_Active)
if(!cvar("menu_video_played"))
{
- localcmd("cd loop $menu_cdtrack; play sound/announcer/default/welcome.ogg\n");
+ localcmd("cd loop $menu_cdtrack; play sound/announcer/default/welcome.wav\n");
menuLogoAlpha = -0.8; // no idea why, but when I start this at zero, it jumps instead of fading FIXME
}
// ALWAYS set this cvar; if we start but menu is not active, this means we want no background music!
SKINVECTOR(COLOR_INPUTBOX_F, '1 1 1');
SKINFLOAT(MARGIN_INPUTBOX_CHARS, 1);
+ // item: clear button
+ SKINSTRING(GFX_CLEARBUTTON, "clearbutton");
+ SKINFLOAT(OFFSET_CLEARBUTTON, 0);
+ SKINVECTOR(COLOR_CLEARBUTTON_N, '1 1 1');
+ SKINVECTOR(COLOR_CLEARBUTTON_F, '1 1 1');
+ SKINVECTOR(COLOR_CLEARBUTTON_C, '1 1 1');
+
// item: key grabber
SKINVECTOR(COLOR_KEYGRABBER_TITLES, '1 1 1');
SKINFLOAT(ALPHA_KEYGRABBER_TITLES, 1);
return 0;
}
c = y * 16 + x;
- if(c != me.mouseSelectedCharacterCell)
+ if(c != me.mouseSelectedCharacterCell || me.mouseSelectedCharacterCell != me.selectedCharacterCell)
me.mouseSelectedCharacterCell = me.selectedCharacterCell = c;
return 1;
}
me.TR(me);
me.TDempty(me, 0.2);
me.TD(me, 1, 1.2, makeXonoticTextLabel(0, _("Teams:")));
- me.TD(me, 1, 1.6, e = makeXonoticTextSlider("g_tdm_teams_override g_domination_teams_override g_keyhunt_teams_override"));
+ me.TD(me, 1, 1.6, e = makeXonoticTextSlider("g_tdm_teams_override g_domination_teams_override g_ca_teams_override g_freezetag_teams_override g_keyhunt_teams_override"));
e.addValue(e, "Default", "0");
e.addValue(e, "2 teams", "2");
e.addValue(e, "3 teams", "3");
s = strcat(s, ", ", _("No powerups"));
if(cvar("g_powerups") > 0)
s = strcat(s, ", ", _("Powerups"));
+ if(cvar("g_touchexplode") > 0)
+ s = strcat(s, ", ", _("Touch explode"));
if(s == "")
return ZCTX(_("MUT^None"));
else
return substring(s, 2, strlen(s) - 2);
}
-
-
-// WARNING: dirty hack. TODO clean this up by putting this behaviour in extra classes.
-void loadCvarsLaserWeaponArenaWeaponButton(entity me)
-{
- tokenize_console(cvar_string("g_weaponarena"));
- me.checked = (argv(0) == me.cvarValue);
-}
-
-void saveCvarsLaserWeaponArenaWeaponButton(entity me)
-{
- string suffix;
-
- suffix = "";
- if(me.cvarValue != "laser" && me.cvarValue != "most")
- if(cvar("menu_weaponarena_with_laser"))
- suffix = " laser";
- if(me.checked)
- cvar_set("g_weaponarena", strcat(me.cvarValue, suffix));
- else
- cvar_set("g_weaponarena", me.cvarOffValue);
-}
-
-.void(entity) draw_weaponarena;
-.void(entity) saveCvars_weaponarena;
-void saveCvarsLaserWeaponArenaLaserButton(entity me)
-{
- // run the old function
- me.saveCvars_weaponarena(me);
-
- me.disabled = ((cvar_string("g_weaponarena") == "0") || (cvar_string("g_weaponarena") == "laser") || (cvar_string("g_weaponarena") == "most"));
-
- if not(me.disabled)
- {
- // check for the laser suffix
- string s;
- s = cvar_string("g_weaponarena");
- if(me.checked && substring(s, strlen(s) - 6, 6) != " laser")
- s = strcat(s, " laser");
- else if(!me.checked && substring(s, strlen(s) - 6, 6) == " laser")
- s = substring(s, 0, strlen(s) - 6);
- cvar_set("g_weaponarena", s);
- }
-}
-
-void preDrawLaserWeaponArenaLaserButton(entity me)
-{
- me.disabled = ((cvar_string("g_weaponarena") == "0") || (cvar_string("g_weaponarena") == "laser") || (cvar_string("g_weaponarena") == "most"));
- // run the old function
- me.draw_weaponarena(me);
-}
-// WARNING: end of dirty hack. Do not try this at home.
-
float checkCompatibility_pinata(entity me)
{
if(cvar("g_minstagib"))
return 0;
return 1;
}
+float checkCompatibility_weaponarena_weapon(entity me)
+{
+ if(cvar("g_minstagib"))
+ return 0;
+ if(cvar_string("g_weaponarena") == "most")
+ return 0;
+ if(cvar_string("g_weaponarena") == "all")
+ return 0;
+ if(cvar_string("g_weaponarena") == "0")
+ return 0;
+ if(cvar_string("g_start_weapon_laser") == "0")
+ return 0;
+ return 1;
+}
void XonoticMutatorsDialog_fill(entity me)
{
entity e, s, w;
float i, j;
- string str, hstr;
me.TR(me);
me.TD(me, 1, 2, makeXonoticTextLabel(0, _("Gameplay mutators:")));
me.TR(me);
me.TDempty(me, 0.2);
me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_dodging", _("Dodging")));
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_touchexplode", _("Touch explode")));
me.TR(me);
me.TDempty(me, 0.2);
me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_cloaked", _("Cloaked")));
me.TR(me);
me.gotoRC(me, 0, 2); me.setFirstColumn(me, me.currentColumn);
- me.TD(me, 1, 4, makeXonoticTextLabel(0, _("Weapon arenas:")));
+ me.TD(me, 1, 2, e = makeXonoticRadioButton(1, string_null, string_null, _("Regular (no arena)")));
me.TR(me);
- me.TDempty(me, 0.2);
- me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, string_null, string_null, _("Regular (no arena)")));
+ me.TD(me, 1, 2, e = makeXonoticRadioButton(1, "g_weaponarena", "menu_weaponarena", _("Weapon arenas:")));
+ e.getCvarValueFromCvar = TRUE;
+ e.cvarOffValue = "0";
for(i = WEP_FIRST, j = 0; i <= WEP_LAST; ++i)
{
w = get_weaponinfo(i);
continue;
if(j & 1 == 0)
me.TR(me);
- str = w.netname;
- hstr = w.message;
me.TDempty(me, 0.2);
- me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_weaponarena", strzone(str), strzone(hstr)));
- e.cvarOffValue = "0";
- // custom load/save logic that ignores a " laser" suffix, or adds it
- e.loadCvars = loadCvarsLaserWeaponArenaWeaponButton;
- e.saveCvars = saveCvarsLaserWeaponArenaWeaponButton;
- e.loadCvars(e);
+ me.TD(me, 1, 1.8, e = makeXonoticWeaponarenaCheckBox(strzone(w.netname), strzone(w.message)));
+ setDependentWeird(e, checkCompatibility_weaponarena_weapon);
++j;
}
me.TR(me);
me.TDempty(me, 0.2);
- me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "menu_weaponarena_with_laser", _("with laser")));
- // hook the draw function to gray it out
- e.draw_weaponarena = e.draw;
- e.draw = preDrawLaserWeaponArenaLaserButton;
- // hook the save function to notify about the cvar
- e.saveCvars_weaponarena = e.saveCvars;
- e.saveCvars = saveCvarsLaserWeaponArenaLaserButton;
+ me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_weaponarena", "most", _("Most weapons")));
+ e.cvarOffValue = "0";
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_weaponarena", "all", _("All weapons")));
+ e.cvarOffValue = "0";
me.TR(me);
me.TD(me, 1, 4, makeXonoticTextLabel(0, _("Special arenas:")));
me.TR(me);
me.TDempty(me, 0.2);
- me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_minstagib", string_null, _("MinstaGib")));
+ me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_minstagib", "1", _("MinstaGib")));
+ e.cvarOffValue = "0";
me.TR(me);
me.TDempty(me, 0.2);
- me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_nix", string_null, _("NIX")));
+ me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_nix", "1", _("NIX")));
+ e.cvarOffValue = "0";
me.TR(me);
me.TDempty(me, 0.4);
me.TD(me, 1, 1.6, e = makeXonoticCheckBox(0, "g_nix_with_laser", _("with laser")));
setDependent(e, "g_nix", 1, 1);
- me.TR(me);
- me.TDempty(me, 0.2);
- me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_weaponarena", "most", _("Most weapons")));
- e.cvarOffValue = "0";
me.TR(me);
me.TDempty(me, 0.2);
me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_start_weapon_laser", "0", _("No start weapons")));
e.cvarOffValue = "-1";
- makeMulti(e, "g_start_weapon_shotgun g_start_weapon_uzi g_start_weapon_grenadelauncher g_start_weapon_minelayer g_start_weapon_electro g_start_weapon_crylink g_start_weapon_nex g_start_weapon_hagar g_start_weapon_rocketlauncher g_start_weapon_rifle g_start_weapon_hlac g_start_weapon_seeker g_start_weapon_minstanex g_start_weapon_hook g_start_weapon_porto g_start_weapon_tuba g_start_weapon_minelayer");
+ makeMulti(e, "g_start_weapon_shotgun g_start_weapon_uzi g_start_weapon_grenadelauncher g_start_weapon_minelayer g_start_weapon_electro g_start_weapon_crylink g_start_weapon_nex g_start_weapon_hagar g_start_weapon_rocketlauncher g_start_weapon_porto g_start_weapon_minstanex g_start_weapon_hook g_start_weapon_hlac g_start_weapon_rifle g_start_weapon_fireball g_start_weapon_seeker g_start_weapon_tuba");
me.gotoRC(me, me.rows - 1, 0);
me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
}
void XonoticDemoBrowserTab_fill(entity me)
{
- entity e;
- entity btn;
- entity dlist;
+ entity e, dlist;
me.TR(me);
me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "cl_autodemo", _("Automatically record demos while playing")));
me.TR(me);
me.TR(me);
me.TD(me, 1, 0.5, e = makeXonoticTextLabel(0, _("Filter:")));
- me.TD(me, 1, 0.5, btn = makeXonoticButton(_("Clear"), '0 0 0'));
- btn.onClick = InputBox_Clear_Click;
- me.TD(me, 1, 3, e = makeXonoticInputBox(0, string_null));
+ me.TD(me, 1, 3.5, e = makeXonoticInputBox(0, string_null));
dlist = makeXonoticDemoList();
e.onChange = DemoList_Filter_Change;
e.onChangeEntity = dlist;
- btn.onClickEntity = e;
dlist.controlledTextbox = e;
me.TR(me);
}
void XonoticServerListTab_fill(entity me)
{
- entity e, slist, btn;
+ entity e, slist;
slist = makeXonoticServerList();
me.TR(me);
me.TD(me, 1, 0.4, e = makeXonoticTextLabel(0, _("Filter:")));
- me.TD(me, 1, 0.6, btn = makeXonoticButton(_("Clear"), '0 0 0'));
- btn.onClick = InputBox_Clear_Click;
- me.TD(me, 1, me.columns - 0.6 * 4 - 0.4, e = makeXonoticInputBox(0, string_null));
+ me.TD(me, 1, me.columns - 0.6 * 3 - 0.4, e = makeXonoticInputBox(0, string_null));
e.onChange = ServerList_Filter_Change;
e.onChangeEntity = slist;
- btn.onClickEntity = e;
slist.controlledTextbox = e;
me.TD(me, 1, 0.6, e = makeXonoticCheckBox(0, "menu_slist_showempty", ZCTX(_("SRVS^Empty"))));
slist.filterShowEmpty = e.checked;
box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
box.maxLength = -127; // negative means encoded length in bytes
box.saveImmediately = 1;
+ box.enableClearButton = 0;
label.textEntity = box;
me.TR(me);
me.TD(me, 5, 1, e = makeXonoticColorpicker(box));
me.TDempty(me, 0.2);
me.TD(me, 1, 1.8, e = makeXonoticTextLabel(0, _("Client UDP port:")));
me.TD(me, 1, 1, e = makeXonoticInputBox(0, "cl_port"));
+ e.enableClearButton = 0;
me.TR(me);
me.TR(me);
me.TDempty(me, 0.2);
}
void XonoticCvarsDialog_fill(entity me) // in this dialog, use SKINCOLOR_CVARLIST_CONTROLS to color ALL controls
{
- entity e, cvarlist, btn;
-
+
+ entity e, cvarlist;
+
cvarlist = makeXonoticCvarList();
-
+
cvarlist.color =
cvarlist.colorF =
cvarlist.color2 =
cvarlist.colorC =
SKINCOLOR_CVARLIST_CONTROLS;
-
+
me.TR(me);
me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Cvar filter:")));
- me.TD(me, 1, 0.5, btn = makeXonoticButton(_("Clear"), SKINCOLOR_CVARLIST_CONTROLS));
- me.TD(me, 1, me.columns - 1.5, e = makeXonoticInputBox(0, string_null));
+ me.TD(me, 1, me.columns - 1, e = makeXonoticInputBox(0, string_null));
e.color = SKINCOLOR_CVARLIST_CONTROLS;
e.colorF = SKINCOLOR_CVARLIST_CONTROLS;
+ e.cb_color = SKINCOLOR_CVARLIST_CONTROLS;
+ e.cb_colorC = SKINCOLOR_CVARLIST_CONTROLS;
+ e.cb_colorF = SKINCOLOR_CVARLIST_CONTROLS;
e.onChange = CvarList_Filter_Change;
e.onChangeEntity = cvarlist;
- btn.onClick = InputBox_Clear_Click;
- btn.onClickEntity = e;
cvarlist.controlledTextbox = e; // this COULD also be the Value box, but this leads to accidentally editing stuff
me.TR(me);
me.TD(me, me.rows - me.currentRow - 7, me.columns, cvarlist);
cvarlist.cvarValueBox = e;
e.color = SKINCOLOR_CVARLIST_CONTROLS;
e.colorF = SKINCOLOR_CVARLIST_CONTROLS;
+ e.cb_color = SKINCOLOR_CVARLIST_CONTROLS;
+ e.cb_colorC = SKINCOLOR_CVARLIST_CONTROLS;
+ e.cb_colorF = SKINCOLOR_CVARLIST_CONTROLS;
e.onChange = CvarList_Value_Change;
e.onChangeEntity = cvarlist;
e.onEnter = CvarList_End_Editing;
ATTRIB(XonoticInputBox, alpha, float, SKINALPHA_TEXT)
+ // Clear button attributes
+ ATTRIB(XonoticInputBox, cb_offset, float, SKINOFFSET_CLEARBUTTON) // bound to range -1, 0
+ ATTRIB(XonoticInputBox, cb_src, string, SKINGFX_CLEARBUTTON)
+ ATTRIB(XonoticInputBox, cb_color, vector, SKINCOLOR_CLEARBUTTON_N)
+ ATTRIB(XonoticInputBox, cb_colorF, vector, SKINCOLOR_CLEARBUTTON_F)
+ ATTRIB(XonoticInputBox, cb_colorC, vector, SKINCOLOR_CLEARBUTTON_C)
+
ATTRIB(XonoticInputBox, cvarName, string, string_null)
METHOD(XonoticInputBox, loadCvars, void(entity))
METHOD(XonoticInputBox, saveCvars, void(entity))
ATTRIB(XonoticRadioButton, cvarName, string, string_null)
ATTRIB(XonoticRadioButton, cvarValue, string, string_null)
ATTRIB(XonoticRadioButton, cvarOffValue, string, string_null)
+ ATTRIB(XonoticRadioButton, getCvarValueFromCvar, float, 0)
METHOD(XonoticRadioButton, loadCvars, void(entity))
METHOD(XonoticRadioButton, saveCvars, void(entity))
if(me.cvarName)
{
if(me.checked)
- cvar_set(me.cvarName, me.cvarValue);
+ {
+ if(me.getCvarValueFromCvar)
+ cvar_set(me.cvarName, cvar_string(me.cvarValue));
+ else
+ cvar_set(me.cvarName, me.cvarValue);
+ }
else if(me.cvarOffValue)
cvar_set(me.cvarName, me.cvarOffValue);
}
--- /dev/null
+#ifdef INTERFACE
+CLASS(XonoticWeaponarenaCheckBox) EXTENDS(CheckBox)
+ METHOD(XonoticWeaponarenaCheckBox, configureXonoticWeaponarenaCheckBox, void(entity, string, string))
+ METHOD(XonoticWeaponarenaCheckBox, setChecked, void(entity, float))
+ ATTRIB(XonoticWeaponarenaCheckBox, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(XonoticWeaponarenaCheckBox, image, string, SKINGFX_CHECKBOX)
+ ATTRIB(XonoticWeaponarenaCheckBox, netname, string, string_null)
+
+ METHOD(XonoticWeaponarenaCheckBox, loadCvars, void(entity))
+ METHOD(XonoticWeaponarenaCheckBox, saveCvars, void(entity))
+ENDCLASS(XonoticWeaponarenaCheckBox)
+entity makeXonoticWeaponarenaCheckBox(string, string);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticWeaponarenaCheckBox(string theWeapon, string theText)
+{
+ entity me;
+ me = spawnXonoticWeaponarenaCheckBox();
+ me.configureXonoticWeaponarenaCheckBox(me, theWeapon, theText);
+ return me;
+}
+void XonoticWeaponarenaCheckBox_configureXonoticWeaponarenaCheckBox(entity me, string theWeapon, string theText)
+{
+ me.netname = theWeapon;
+ me.checked = FALSE;
+ me.loadCvars(me);
+ me.configureCheckBox(me, theText, me.fontSize, me.image);
+}
+void XonoticWeaponarenaCheckBox_setChecked(entity me, float foo)
+{
+ me.checked = !me.checked;
+ me.saveCvars(me);
+}
+void XonoticWeaponarenaCheckBox_loadCvars(entity me)
+{
+ float n = tokenize_console(cvar_string("menu_weaponarena"));
+ float i;
+ for(i=0; i<n; ++i)
+ {
+ if(argv(i) == me.netname)
+ {
+ me.checked = TRUE;
+ break;
+ }
+ }
+}
+
+void XonoticWeaponarenaCheckBox_saveCvars(entity me)
+{
+ if(me.checked)
+ localcmd(strcat("\nmenu_cmd addtolist menu_weaponarena ", me.netname, "\n"));
+ else
+ localcmd(strcat("\nmenu_cmd removefromlist menu_weaponarena ", me.netname, "\n"));
+ localcmd("\ng_weaponarena \"$menu_weaponarena\"\n");
+}
+#endif
+++ /dev/null
-float maxspawned;
-float numspawned;
-float arena_roundbased;
-.float spawned;
-.entity spawnqueue_next;
-.entity spawnqueue_prev;
-.float spawnqueue_in;
-entity spawnqueue_first;
-entity spawnqueue_last;
-entity champion;
-float warmup;
-.float caplayer;
-
-void PutObserverInServer();
-void PutClientInServer();
-
-float next_round;
-float redalive, bluealive, yellowalive, pinkalive;
-float totalalive;
-.float redalive_stat, bluealive_stat, yellowalive_stat, pinkalive_stat;
-float red_players, blue_players, yellow_players, pink_players;
-float total_players;
-
-/**
- * Resets the state of all clients, items, flags, keys, weapons, waypoints, ... of the map.
- * Sets the 'warmup' global variable.
- */
-void reset_map(float dorespawn)
-{
- entity oldself;
- oldself = self;
-
- if(g_arena && autocvar_g_arena_warmup)
- warmup = time + autocvar_g_arena_warmup;
- else if(g_ca) {
- warmup = time + autocvar_g_ca_warmup;
- allowed_to_spawn = 1;
- }
- else if(g_freezetag)
- {
- warmup = time + autocvar_g_freezetag_warmup;
- }
-
- lms_lowest_lives = 999;
- lms_next_place = player_count;
-
- race_ReadyRestart();
-
- for(self = world; (self = nextent(self)); )
- if(clienttype(self) == CLIENTTYPE_NOTACLIENT)
- {
- if(self.reset)
- {
- self.reset();
- continue;
- }
-
- if(self.team_saved)
- self.team = self.team_saved;
-
- if(self.flags & FL_PROJECTILE) // remove any projectiles left
- remove(self);
- }
-
- // Waypoints and assault start come LAST
- for(self = world; (self = nextent(self)); )
- if(clienttype(self) == CLIENTTYPE_NOTACLIENT)
- {
- if(self.reset2)
- {
- self.reset2();
- continue;
- }
- }
-
- // Moving the player reset code here since the player-reset depends
- // on spawnpoint entities which have to be reset first --blub
- if(dorespawn)
- FOR_EACH_CLIENT(self) {
- if(self.flags & FL_CLIENT) // reset all players
- {
- if(g_arena)
- {
- if(self.spawned)
- PutClientInServer();
- else
- PutObserverInServer();
- }
- else if(g_ca && self.caplayer) {
- self.classname = "player";
- PutClientInServer();
- }
- else if(g_freezetag)
- {
- if(self.classname == "player")
- PutClientInServer();
- }
- else
- {
- /*
- only reset players if a restart countdown is active
- this can either be due to cvar sv_ready_restart_after_countdown having set
- restart_mapalreadyrestarted to 1 after the countdown ended or when
- sv_ready_restart_after_countdown is not used and countdown is still running
- */
- if (restart_mapalreadyrestarted || (time < game_starttime))
- {
- //NEW: changed behaviour so that it prevents that previous spectators/observers suddenly spawn as players
- if (self.classname == "player") {
- //PlayerScore_Clear(self);
- if(g_lms)
- PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives());
- self.killcount = 0;
- //stop the player from moving so that he stands still once he gets respawned
- self.velocity = '0 0 0';
- self.avelocity = '0 0 0';
- self.movement = '0 0 0';
- PutClientInServer();
- }
- }
- }
- }
- }
-
- if(g_keyhunt)
- kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round+(game_starttime - time), kh_StartRound);
-
- if(g_arena)
- if(champion && champion.classname == "player" && player_count > 1)
- UpdateFrags(champion, +1);
-
- self = oldself;
-}
-
-void Spawnqueue_Insert(entity e)
-{
- if(e.spawnqueue_in)
- return;
- dprint(strcat("Into queue: ", e.netname, "\n"));
- e.spawnqueue_in = TRUE;
- e.spawnqueue_prev = spawnqueue_last;
- e.spawnqueue_next = world;
- if(spawnqueue_last)
- spawnqueue_last.spawnqueue_next = e;
- spawnqueue_last = e;
- if(!spawnqueue_first)
- spawnqueue_first = e;
-}
-
-void Spawnqueue_Remove(entity e)
-{
- if(!e.spawnqueue_in)
- return;
- dprint(strcat("Out of queue: ", e.netname, "\n"));
- e.spawnqueue_in = FALSE;
- if(e == spawnqueue_first)
- spawnqueue_first = e.spawnqueue_next;
- if(e == spawnqueue_last)
- spawnqueue_last = e.spawnqueue_prev;
- if(e.spawnqueue_prev)
- e.spawnqueue_prev.spawnqueue_next = e.spawnqueue_next;
- if(e.spawnqueue_next)
- e.spawnqueue_next.spawnqueue_prev = e.spawnqueue_prev;
- e.spawnqueue_next = world;
- e.spawnqueue_prev = world;
-}
-
-void Spawnqueue_Unmark(entity e)
-{
- if(!e.spawned)
- return;
- e.spawned = FALSE;
- numspawned = numspawned - 1;
-}
-
-void Spawnqueue_Mark(entity e)
-{
- if(e.spawned)
- return;
- e.spawned = TRUE;
- numspawned = numspawned + 1;
-}
-
-/**
- * If roundbased arena game mode is active, it centerprints the texts for the
- * player when player is waiting for the countdown to finish.
- * Blocks the players movement while countdown is active.
- * Unblocks the player once the countdown is over.
- *
- * Called in StartFrame()
- */
-float roundStartTime_prev; // prevent networkspam
-void Arena_Warmup()
-{
- float f;
- entity e;
-
- if(gameover)
- {
- if(warmup && time < warmup)
- {
- Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_ARENA);
- warmup = 0;
- }
- if(champion && g_arena)
- {
- FOR_EACH_REALCLIENT(e)
- centerprint(e, strcat("The Champion is ", champion.netname));
- champion = world;
- }
- return;
- }
- if((!g_arena && !g_ca && !g_freezetag) || (g_arena && !arena_roundbased) || (time < game_starttime))
- return;
-
- f = ceil(warmup - time);
-
- if(inWarmupStage)
- allowed_to_spawn = 1;
- else if(!g_ca)
- allowed_to_spawn = 0;
-
- if(time < warmup && !inWarmupStage)
- {
- if (g_ca)
- allowed_to_spawn = 1;
- if(champion && g_arena)
- {
- FOR_EACH_REALCLIENT(e)
- centerprint(e, strcat("The Champion is ", champion.netname));
- }
-
- if(f != roundStartTime_prev) {
- roundStartTime_prev = f;
- if(g_ca && !(red_players && blue_players)) {
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ARENA_NEEDPLAYER);
- warmup = time + autocvar_g_ca_warmup;
- } else {
- if(f == 5)
- Announce("prepareforbattle");
- else if(f == 3)
- Announce("3");
- else if(f == 2)
- Announce("2");
- else if(f == 1)
- Announce("1");
-
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ARENA_ROUNDSTART, f);
- }
- }
-
- if (g_arena) {
- FOR_EACH_CLIENT(e)
- {
- if(e.spawned && e.classname == "player")
- e.player_blocked = 1;
- }
- }
- }
- else if(f > -1 && f != roundStartTime_prev)
- {
- roundStartTime_prev = f;
- if(g_ca) {
- if(red_players && blue_players)
- allowed_to_spawn = 0;
- else
- reset_map(TRUE);
- } else {
- Announce("begin");
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ARENA_BEGIN);
- }
-
- if(g_arena) {
- FOR_EACH_CLIENT(e)
- {
- if(e.player_blocked)
- e.player_blocked = 0;
- }
- }
- }
-
- // clear champion to avoid centerprinting again the champion msg
- if (champion)
- champion = world;
-}
-
-void count_players()
-{
- // count amount of players in each team
- total_players = red_players = blue_players = yellow_players = pink_players = 0;
- FOR_EACH_PLAYER(self) {
- if (self.team == NUM_TEAM_1)
- {
- red_players += 1;
- total_players += 1;
- }
- else if (self.team == NUM_TEAM_2)
- {
- blue_players += 1;
- total_players += 1;
- }
- else if (self.team == NUM_TEAM_3)
- {
- yellow_players += 1;
- total_players += 1;
- }
- else if (self.team == NUM_TEAM_4)
- {
- pink_players += 1;
- total_players += 1;
- }
- }
-}
-
-void count_alive_players()
-{
- totalalive = redalive = bluealive = yellowalive = pinkalive = 0;
- if(g_ca)
- {
- FOR_EACH_PLAYER(self) {
- if (self.team == NUM_TEAM_1 && self.health >= 1)
- {
- redalive += 1;
- totalalive += 1;
- }
- else if (self.team == NUM_TEAM_2 && self.health >= 1)
- {
- bluealive += 1;
- totalalive += 1;
- }
- }
- FOR_EACH_REALCLIENT(self) {
- self.redalive_stat = redalive;
- self.bluealive_stat = bluealive;
- }
- }
- else if(g_freezetag)
- {
- // count amount of alive players in each team
- FOR_EACH_PLAYER(self) {
- if (self.team == NUM_TEAM_1 && self.freezetag_frozen == 0 && self.health >= 1)
- {
- redalive += 1;
- totalalive += 1;
- }
- else if (self.team == NUM_TEAM_2 && self.freezetag_frozen == 0 && self.health >= 1)
- {
- bluealive += 1;
- totalalive += 1;
- }
- else if (self.team == NUM_TEAM_3 && self.freezetag_frozen == 0 && self.health >= 1)
- {
- yellowalive += 1;
- totalalive += 1;
- }
- else if (self.team == NUM_TEAM_4 && self.freezetag_frozen == 0 && self.health >= 1)
- {
- pinkalive += 1;
- totalalive += 1;
- }
- }
- FOR_EACH_REALCLIENT(self) {
- self.redalive_stat = redalive;
- self.bluealive_stat = bluealive;
- self.yellowalive_stat = yellowalive;
- self.pinkalive_stat = pinkalive;
- }
- }
-
-}
-
-/**
- * This function finds out whether an arena round is over 1 player is left.
- * It determines the last player who's still alive and saves it's entity reference
- * in the global variable 'champion'. Then the new enemy/enemies are put into the server.
- *
- * Gets called in StartFrame()
- */
-void Spawnqueue_Check()
-{
- if(warmup == 0 && g_ca && !inWarmupStage)
- {
- if(red_players || blue_players)
- reset_map(TRUE);
- return;
- }
- if(time < warmup + 1 || inWarmupStage || intermission_running)
- return;
-
- if(g_ca) {
- if(allowed_to_spawn) // round is not started yet
- return;
- if(!next_round) {
- if(!(redalive && bluealive)) {
- // every player of (at least) one team is dead, round ends here
- if(redalive) {
- play2all("ctf/red_capture.wav");
- FOR_EACH_CLIENT(self) centerprint(self, "^1RED ^7team wins the round");
- TeamScore_AddToTeam(NUM_TEAM_1, ST_SCORE, +1);
- }
- else if(bluealive) {
- play2all("ctf/blue_capture.wav");
- FOR_EACH_CLIENT(self) centerprint(self, "^4BLUE ^7team wins the round");
- TeamScore_AddToTeam(NUM_TEAM_2, ST_SCORE, +1);
- }
- else
- FOR_EACH_CLIENT(self) centerprint(self, "^7Round tied");
- next_round = -1;
- }
- else if(time - warmup > autocvar_g_ca_round_timelimit) {
- FOR_EACH_CLIENT(self) centerprint(self, "^7Round tied");
- next_round = time + 5;
- }
- }
- else if(next_round == -1) {
- // wait for killed players to be put as spectators
- if(!(red_players && blue_players))
- next_round = time + 5;
- }
- else if((next_round > 0 && next_round < time))
- {
- next_round = 0;
- reset_map(TRUE);
- }
- } else if(g_freezetag) {
- if((next_round && next_round < time))
- {
- next_round = 0;
- reset_map(TRUE);
- }
- } else { // arena
- //extend next_round if it isn't set yet and only 1 player is spawned
- if(!next_round)
- if(numspawned < 2)
- next_round = time + 3;
-
- if(!arena_roundbased || (next_round && next_round < time && player_count > 1))
- {
- next_round = 0;
-
- if(arena_roundbased)
- {
- champion = find(world, classname, "player");
- while(champion && champion.deadflag)
- champion = find(champion, classname, "player");
- reset_map(TRUE);
- }
-
- while(numspawned < maxspawned && spawnqueue_first)
- {
- self = spawnqueue_first;
-
- bprint ("^4", self.netname, "^4 is the next challenger\n");
-
- Spawnqueue_Remove(self);
- Spawnqueue_Mark(self);
-
- self.classname = "player";
- PutClientInServer();
- }
- }
- }
-}
+++ /dev/null
-void spawnfunc_func_breakable();
-void target_objective_decrease_activate();
-.entity assault_decreaser;
-.entity assault_sprite;
-
-void spawnfunc_info_player_attacker() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
- self.team = NUM_TEAM_1; // red, gets swapped every round
- spawnfunc_info_player_deathmatch();
-}
-
-void spawnfunc_info_player_defender() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
- self.team = NUM_TEAM_2; // blue, gets swapped every round
- spawnfunc_info_player_deathmatch();
-}
-
-// reset this objective. Used when spawning an objective
-// and when a new round starts
-void assault_objective_reset() {
- self.health = ASSAULT_VALUE_INACTIVE;
-}
-
-void assault_objective_use() {
- // activate objective
- self.health = 100;
- //print("^2Activated objective ", self.targetname, "=", etos(self), "\n");
- //print("Activator is ", activator.classname, "\n");
-
- entity oldself;
- oldself = self;
-
- for(self = world; (self = find(self, target, oldself.targetname)); )
- {
- if(self.classname == "target_objective_decrease")
- target_objective_decrease_activate();
- }
-
- self = oldself;
-}
-
-vector target_objective_spawn_evalfunc(entity player, entity spot, vector current)
-{
- if(self.health < 0 || self.health >= ASSAULT_VALUE_INACTIVE)
- return '-1 0 0';
- return current;
-}
-
-void spawnfunc_target_objective() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
- self.classname = "target_objective";
- self.use = assault_objective_use;
- assault_objective_reset();
- self.reset = assault_objective_reset;
- self.spawn_evalfunc = target_objective_spawn_evalfunc;
-}
-
-
-// decrease the health of targeted objectives
-void assault_objective_decrease_use() {
- if(activator.team != assault_attacker_team) {
- // wrong team triggered decrease
- return;
- }
-
- if(other.assault_sprite)
- {
- WaypointSprite_Disown(other.assault_sprite, waypointsprite_deadlifetime);
- if(other.classname == "func_assault_destructible")
- other.sprite = world;
- }
- else
- return; // already activated! cannot activate again!
-
- if(self.enemy.health < ASSAULT_VALUE_INACTIVE)
- {
- if(self.enemy.health - self.dmg > 0.5)
- {
- PlayerTeamScore_Add(activator, SP_SCORE, ST_SCORE, self.dmg);
- self.enemy.health = self.enemy.health - self.dmg;
- }
- else
- {
- PlayerTeamScore_Add(activator, SP_SCORE, ST_SCORE, self.enemy.health);
- PlayerTeamScore_Add(activator, SP_ASSAULT_OBJECTIVES, ST_ASSAULT_OBJECTIVES, 1);
- self.enemy.health = -1;
-
- entity oldself, oldactivator;
-
- oldself = self;
- self = oldself.enemy;
- if(self.message)
- {
- entity player;
- string s;
- FOR_EACH_PLAYER(player)
- {
- s = strcat(self.message, "\n");
- centerprint(player, s);
- }
- }
-
- oldactivator = activator;
- activator = oldself;
- SUB_UseTargets();
- activator = oldactivator;
- self = oldself;
- }
- }
-}
-
-void assault_setenemytoobjective()
-{
- entity objective;
- for(objective = world; (objective = find(objective, targetname, self.target)); ) {
- if(objective.classname == "target_objective") {
- if(self.enemy == world)
- self.enemy = objective;
- else
- objerror("more than one objective as target - fix the map!");
- break;
- }
- }
-
- if(self.enemy == world)
- objerror("no objective as target - fix the map!");
-}
-
-float assault_decreaser_sprite_visible(entity e)
-{
- entity decreaser;
-
- decreaser = self.assault_decreaser;
-
- if(decreaser.enemy.health >= ASSAULT_VALUE_INACTIVE)
- return FALSE;
-
- return TRUE;
-}
-
-void target_objective_decrease_activate()
-{
- entity ent, spr;
- self.owner = world;
- for(ent = world; (ent = find(ent, target, self.targetname)); )
- {
- if(ent.assault_sprite != world)
- {
- WaypointSprite_Disown(ent.assault_sprite, waypointsprite_deadlifetime);
- if(ent.classname == "func_assault_destructible")
- ent.sprite = world;
- }
-
- spr = WaypointSprite_SpawnFixed("<placeholder>", 0.5 * (ent.absmin + ent.absmax), ent, assault_sprite, RADARICON_OBJECTIVE, '1 0.5 0');
- spr.assault_decreaser = self;
- spr.waypointsprite_visible_for_player = assault_decreaser_sprite_visible;
- spr.classname = "sprite_waypoint";
- WaypointSprite_UpdateRule(spr, assault_attacker_team, SPRITERULE_TEAMPLAY);
- if(ent.classname == "func_assault_destructible")
- {
- WaypointSprite_UpdateSprites(spr, "as-defend", "as-destroy", "as-destroy");
- WaypointSprite_UpdateMaxHealth(spr, ent.max_health);
- WaypointSprite_UpdateHealth(spr, ent.health);
- ent.sprite = spr;
- }
- else
- WaypointSprite_UpdateSprites(spr, "as-defend", "as-push", "as-push");
- }
-}
-
-void target_objective_decrease_findtarget()
-{
- assault_setenemytoobjective();
-}
-
-//=============================================================================
-
-void spawnfunc_target_objective_decrease() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
-
- self.classname = "target_objective_decrease";
-
- if(!self.dmg) {
- self.dmg = 101;
- }
- self.use = assault_objective_decrease_use;
- self.health = ASSAULT_VALUE_INACTIVE;
- self.max_health = ASSAULT_VALUE_INACTIVE;
- self.enemy = world;
-
- InitializeEntity(self, target_objective_decrease_findtarget, INITPRIO_FINDTARGET);
-}
-
-// destructible walls that can be used to trigger target_objective_decrease
-void spawnfunc_func_assault_destructible() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
- self.spawnflags = 3;
- self.classname = "func_assault_destructible";
- if(assault_attacker_team == NUM_TEAM_1) {
- self.team = NUM_TEAM_2;
- } else {
- self.team = NUM_TEAM_1;
- }
- spawnfunc_func_breakable();
-}
-
-void assault_wall_think() {
- if(self.enemy.health < 0) {
- self.model = "";
- self.solid = SOLID_NOT;
- } else {
- self.model = self.mdl;
- self.solid = SOLID_BSP;
- }
-
- self.nextthink = time + 0.2;
-}
-
-void spawnfunc_func_assault_wall() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
- self.classname = "func_assault_wall";
- self.mdl = self.model;
- setmodel(self, self.mdl);
- self.solid = SOLID_BSP;
- self.think = assault_wall_think;
- self.nextthink = time;
- InitializeEntity(self, assault_setenemytoobjective, INITPRIO_FINDTARGET);
-}
-
-
-void target_assault_roundend_reset() {
- //print("round end reset\n");
- self.cnt = self.cnt + 1; // up round counter
- self.winning = 0; // up round
-}
-
-void target_assault_roundend_use() {
- self.winning = 1; // round has been won by attackers
-}
-
-void spawnfunc_target_assault_roundend() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
- self.winning = 0; // round not yet won by attackers
- self.classname = "target_assault_roundend";
- self.use = target_assault_roundend_use;
- self.cnt = 0; // first round
- self.reset = target_assault_roundend_reset;
-}
-
-void assault_roundstart_use() {
-
- activator = self;
- SUB_UseTargets();
-
-
-#ifdef TTURRETS_ENABLED
- entity ent, oldself;
-
- //(Re)spawn all turrets
- oldself = self;
- ent = find(world, classname, "turret_main");
- while(ent) {
- // Swap turret teams
- if(ent.team == NUM_TEAM_1)
- ent.team = NUM_TEAM_2;
- else
- ent.team = NUM_TEAM_1;
-
- self = ent;
-
- // Dubbles as teamchange
- turret_stdproc_respawn();
-
- ent = find(ent, classname, "turret_main");
- }
- self = oldself;
-#endif
-
-
-}
-
-void spawnfunc_target_assault_roundstart() {
- if(!g_assault)
- {
- remove(self);
- return;
- }
- assault_attacker_team = NUM_TEAM_1;
- self.classname = "target_assault_roundstart";
- self.use = assault_roundstart_use;
- self.reset2 = assault_roundstart_use;
- InitializeEntity(self, assault_roundstart_use, INITPRIO_FINDTARGET);
-}
-
-// trigger new round
-// reset objectives, toggle spawnpoints, reset triggers, ...
-void vehicles_clearrturn();
-void vehicles_spawn();
-void assault_new_round()
-{
- entity oldself;
- //bprint("ASSAULT: new round\n");
-
- oldself = self;
- // Eject players from vehicles
- FOR_EACH_PLAYER(self)
- {
- if(self.vehicle)
- vehicles_exit(VHEF_RELESE);
- }
-
- self = findchainflags(vehicle_flags, VHF_ISVEHICLE);
- while(self)
- {
- vehicles_clearrturn();
- vehicles_spawn();
- self = self.chain;
- }
-
- self = oldself;
-
- // up round counter
- self.winning = self.winning + 1;
-
- // swap attacker/defender roles
- if(assault_attacker_team == NUM_TEAM_1) {
- assault_attacker_team = NUM_TEAM_2;
- } else {
- assault_attacker_team = NUM_TEAM_1;
- }
-
-
- entity ent;
- for(ent = world; (ent = nextent(ent)); )
- {
- if(clienttype(ent) == CLIENTTYPE_NOTACLIENT)
- {
- if(ent.team_saved == NUM_TEAM_1)
- ent.team_saved = NUM_TEAM_2;
- else if(ent.team_saved == NUM_TEAM_2)
- ent.team_saved = NUM_TEAM_1;
- }
- }
-
- // reset the level with a countdown
- cvar_set("timelimit", ftos(ceil(time - game_starttime) / 60));
- ReadyRestart_force(); // sets game_starttime
-}
--- /dev/null
+void spawnfunc_func_breakable();
+void target_objective_decrease_activate();
+.entity assault_decreaser;
+.entity assault_sprite;
+
+void spawnfunc_info_player_attacker() {
+ if(!g_assault)
+ {
+ remove(self);
+ return;
+ }
+ self.team = NUM_TEAM_1; // red, gets swapped every round
+ spawnfunc_info_player_deathmatch();
+}
+
+void spawnfunc_info_player_defender() {
+ if(!g_assault)
+ {
+ remove(self);
+ return;
+ }
+ self.team = NUM_TEAM_2; // blue, gets swapped every round
+ spawnfunc_info_player_deathmatch();
+}
+
+// reset this objective. Used when spawning an objective
+// and when a new round starts
+void assault_objective_reset() {
+ self.health = ASSAULT_VALUE_INACTIVE;
+}
+
+void assault_objective_use() {
+ // activate objective
+ self.health = 100;
+ //print("^2Activated objective ", self.targetname, "=", etos(self), "\n");
+ //print("Activator is ", activator.classname, "\n");
+
+ entity oldself;
+ oldself = self;
+
+ for(self = world; (self = find(self, target, oldself.targetname)); )
+ {
+ if(self.classname == "target_objective_decrease")
+ target_objective_decrease_activate();
+ }
+
+ self = oldself;
+}
+
+vector target_objective_spawn_evalfunc(entity player, entity spot, vector current)
+{
+ if(self.health < 0 || self.health >= ASSAULT_VALUE_INACTIVE)
+ return '-1 0 0';
+ return current;
+}
+
+void spawnfunc_target_objective() {
+ if(!g_assault)
+ {
+ remove(self);
+ return;
+ }
+ self.classname = "target_objective";
+ self.use = assault_objective_use;
+ assault_objective_reset();
+ self.reset = assault_objective_reset;
+ self.spawn_evalfunc = target_objective_spawn_evalfunc;
+}
+
+
+// decrease the health of targeted objectives
+void assault_objective_decrease_use() {
+ if(activator.team != assault_attacker_team) {
+ // wrong team triggered decrease
+ return;
+ }
+
+ if(other.assault_sprite)
+ {
+ WaypointSprite_Disown(other.assault_sprite, waypointsprite_deadlifetime);
+ if(other.classname == "func_assault_destructible")
+ other.sprite = world;
+ }
+ else
+ return; // already activated! cannot activate again!
+
+ if(self.enemy.health < ASSAULT_VALUE_INACTIVE)
+ {
+ if(self.enemy.health - self.dmg > 0.5)
+ {
+ PlayerTeamScore_Add(activator, SP_SCORE, ST_SCORE, self.dmg);
+ self.enemy.health = self.enemy.health - self.dmg;
+ }
+ else
+ {
+ PlayerTeamScore_Add(activator, SP_SCORE, ST_SCORE, self.enemy.health);
+ PlayerTeamScore_Add(activator, SP_ASSAULT_OBJECTIVES, ST_ASSAULT_OBJECTIVES, 1);
+ self.enemy.health = -1;
+
+ entity oldself, oldactivator;
+
+ oldself = self;
+ self = oldself.enemy;
+ if(self.message)
+ {
+ entity player;
+ string s;
+ FOR_EACH_PLAYER(player)
+ {
+ s = strcat(self.message, "\n");
+ centerprint(player, s);
+ }
+ }
+
+ oldactivator = activator;
+ activator = oldself;
+ SUB_UseTargets();
+ activator = oldactivator;
+ self = oldself;
+ }
+ }
+}
+
+void assault_setenemytoobjective()
+{
+ entity objective;
+ for(objective = world; (objective = find(objective, targetname, self.target)); ) {
+ if(objective.classname == "target_objective") {
+ if(self.enemy == world)
+ self.enemy = objective;
+ else
+ objerror("more than one objective as target - fix the map!");
+ break;
+ }
+ }
+
+ if(self.enemy == world)
+ objerror("no objective as target - fix the map!");
+}
+
+float assault_decreaser_sprite_visible(entity e)
+{
+ entity decreaser;
+
+ decreaser = self.assault_decreaser;
+
+ if(decreaser.enemy.health >= ASSAULT_VALUE_INACTIVE)
+ return FALSE;
+
+ return TRUE;
+}
+
+void target_objective_decrease_activate()
+{
+ entity ent, spr;
+ self.owner = world;
+ for(ent = world; (ent = find(ent, target, self.targetname)); )
+ {
+ if(ent.assault_sprite != world)
+ {
+ WaypointSprite_Disown(ent.assault_sprite, waypointsprite_deadlifetime);
+ if(ent.classname == "func_assault_destructible")
+ ent.sprite = world;
+ }
+
+ spr = WaypointSprite_SpawnFixed("<placeholder>", 0.5 * (ent.absmin + ent.absmax), ent, assault_sprite, RADARICON_OBJECTIVE, '1 0.5 0');
+ spr.assault_decreaser = self;
+ spr.waypointsprite_visible_for_player = assault_decreaser_sprite_visible;
+ spr.classname = "sprite_waypoint";
+ WaypointSprite_UpdateRule(spr, assault_attacker_team, SPRITERULE_TEAMPLAY);
+ if(ent.classname == "func_assault_destructible")
+ {
+ WaypointSprite_UpdateSprites(spr, "as-defend", "as-destroy", "as-destroy");
+ WaypointSprite_UpdateMaxHealth(spr, ent.max_health);
+ WaypointSprite_UpdateHealth(spr, ent.health);
+ ent.sprite = spr;
+ }
+ else
+ WaypointSprite_UpdateSprites(spr, "as-defend", "as-push", "as-push");
+ }
+}
+
+void target_objective_decrease_findtarget()
+{
+ assault_setenemytoobjective();
+}
+
+//=============================================================================
+
+void spawnfunc_target_objective_decrease() {
+ if(!g_assault)
+ {
+ remove(self);
+ return;
+ }
+
+ self.classname = "target_objective_decrease";
+
+ if(!self.dmg) {
+ self.dmg = 101;
+ }
+ self.use = assault_objective_decrease_use;
+ self.health = ASSAULT_VALUE_INACTIVE;
+ self.max_health = ASSAULT_VALUE_INACTIVE;
+ self.enemy = world;
+
+ InitializeEntity(self, target_objective_decrease_findtarget, INITPRIO_FINDTARGET);
+}
+
+// destructible walls that can be used to trigger target_objective_decrease
+void spawnfunc_func_assault_destructible() {
+ if(!g_assault)
+ {
+ remove(self);
+ return;
+ }
+ self.spawnflags = 3;
+ self.classname = "func_assault_destructible";
+ if(assault_attacker_team == NUM_TEAM_1) {
+ self.team = NUM_TEAM_2;
+ } else {
+ self.team = NUM_TEAM_1;
+ }
+ spawnfunc_func_breakable();
+}
+
+void assault_wall_think() {
+ if(self.enemy.health < 0) {
+ self.model = "";
+ self.solid = SOLID_NOT;
+ } else {
+ self.model = self.mdl;
+ self.solid = SOLID_BSP;
+ }
+
+ self.nextthink = time + 0.2;
+}
+
+void spawnfunc_func_assault_wall() {
+ if(!g_assault)
+ {
+ remove(self);
+ return;
+ }
+ self.classname = "func_assault_wall";
+ self.mdl = self.model;
+ setmodel(self, self.mdl);
+ self.solid = SOLID_BSP;
+ self.think = assault_wall_think;
+ self.nextthink = time;
+ InitializeEntity(self, assault_setenemytoobjective, INITPRIO_FINDTARGET);
+}
+
+
+void target_assault_roundend_reset() {
+ //print("round end reset\n");
+ self.cnt = self.cnt + 1; // up round counter
+ self.winning = 0; // up round
+}
+
+void target_assault_roundend_use() {
+ self.winning = 1; // round has been won by attackers
+}
+
+void spawnfunc_target_assault_roundend() {
+ if(!g_assault)
+ {
+ remove(self);
+ return;
+ }
+ self.winning = 0; // round not yet won by attackers
+ self.classname = "target_assault_roundend";
+ self.use = target_assault_roundend_use;
+ self.cnt = 0; // first round
+ self.reset = target_assault_roundend_reset;
+}
+
+void assault_roundstart_use() {
+
+ activator = self;
+ SUB_UseTargets();
+
+
+#ifdef TTURRETS_ENABLED
+ entity ent, oldself;
+
+ //(Re)spawn all turrets
+ oldself = self;
+ ent = find(world, classname, "turret_main");
+ while(ent) {
+ // Swap turret teams
+ if(ent.team == NUM_TEAM_1)
+ ent.team = NUM_TEAM_2;
+ else
+ ent.team = NUM_TEAM_1;
+
+ self = ent;
+
+ // Dubbles as teamchange
+ turret_stdproc_respawn();
+
+ ent = find(ent, classname, "turret_main");
+ }
+ self = oldself;
+#endif
+
+
+}
+
+void spawnfunc_target_assault_roundstart() {
+ if(!g_assault)
+ {
+ remove(self);
+ return;
+ }
+ assault_attacker_team = NUM_TEAM_1;
+ self.classname = "target_assault_roundstart";
+ self.use = assault_roundstart_use;
+ self.reset2 = assault_roundstart_use;
+ InitializeEntity(self, assault_roundstart_use, INITPRIO_FINDTARGET);
+}
+
+// trigger new round
+// reset objectives, toggle spawnpoints, reset triggers, ...
+void vehicles_clearrturn();
+void vehicles_spawn();
+void assault_new_round()
+{
+ entity oldself;
+ //bprint("ASSAULT: new round\n");
+
+ oldself = self;
+ // Eject players from vehicles
+ FOR_EACH_PLAYER(self)
+ {
+ if(self.vehicle)
+ vehicles_exit(VHEF_RELESE);
+ }
+
+ self = findchainflags(vehicle_flags, VHF_ISVEHICLE);
+ while(self)
+ {
+ vehicles_clearrturn();
+ vehicles_spawn();
+ self = self.chain;
+ }
+
+ self = oldself;
+
+ // up round counter
+ self.winning = self.winning + 1;
+
+ // swap attacker/defender roles
+ if(assault_attacker_team == NUM_TEAM_1) {
+ assault_attacker_team = NUM_TEAM_2;
+ } else {
+ assault_attacker_team = NUM_TEAM_1;
+ }
+
+
+ entity ent;
+ for(ent = world; (ent = nextent(ent)); )
+ {
+ if(clienttype(ent) == CLIENTTYPE_NOTACLIENT)
+ {
+ if(ent.team_saved == NUM_TEAM_1)
+ ent.team_saved = NUM_TEAM_2;
+ else if(ent.team_saved == NUM_TEAM_2)
+ ent.team_saved = NUM_TEAM_1;
+ }
+ }
+
+ // reset the level with a countdown
+ cvar_set("timelimit", ftos(ceil(time - game_starttime) / 60));
+ ReadyRestart_force(); // sets game_starttime
+}
--- /dev/null
+#define HAVOCBOT_AST_ROLE_NONE 0
+#define HAVOCBOT_AST_ROLE_DEFENSE 2
+#define HAVOCBOT_AST_ROLE_OFFENSE 4
+
+.float havocbot_role_flags;
+.float havocbot_attack_time;
+
+.void() havocbot_role;
+.void() havocbot_previous_role;
+
+void() havocbot_role_ast_defense;
+void() havocbot_role_ast_offense;
+.entity havocbot_ast_target;
+
+void(entity bot) havocbot_ast_reset_role;
+
+void(float ratingscale, vector org, float sradius) havocbot_goalrating_items;
+void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
+
+void havocbot_goalrating_ast_targets(float ratingscale)
+{
+ entity ad, best, wp, tod;
+ float radius, found, bestvalue;
+ vector p;
+
+ ad = findchain(classname, "func_assault_destructible");
+
+ for (; ad; ad = ad.chain)
+ {
+ if (ad.target == "")
+ continue;
+
+ if not(ad.bot_attack)
+ continue;
+
+ found = FALSE;
+ for(tod = world; (tod = find(tod, targetname, ad.target)); )
+ {
+ if(tod.classname == "target_objective_decrease")
+ {
+ if(tod.enemy.health > 0 && tod.enemy.health < ASSAULT_VALUE_INACTIVE)
+ {
+ // dprint(etos(ad),"\n");
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ if(!found)
+ {
+ /// dprint("target not found\n");
+ continue;
+ }
+ /// dprint("target #", etos(ad), " found\n");
+
+
+ p = 0.5 * (ad.absmin + ad.absmax);
+ // dprint(vtos(ad.origin), " ", vtos(ad.absmin), " ", vtos(ad.absmax),"\n");
+ // te_knightspike(p);
+ // te_lightning2(world, '0 0 0', p);
+
+ // Find and rate waypoints around it
+ found = FALSE;
+ best = world;
+ bestvalue = 99999999999;
+ for(radius=0; radius<1500 && !found; radius+=500)
+ {
+ for(wp=findradius(p, radius); wp; wp=wp.chain)
+ {
+ if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
+ if(wp.classname=="waypoint")
+ if(checkpvs(wp.origin, ad))
+ {
+ found = TRUE;
+ if(wp.cnt<bestvalue)
+ {
+ best = wp;
+ bestvalue = wp.cnt;
+ }
+ }
+ }
+ }
+
+ if(best)
+ {
+ /// dprint("waypoints around target were found\n");
+ // te_lightning2(world, '0 0 0', best.origin);
+ // te_knightspike(best.origin);
+
+ navigation_routerating(best, ratingscale, 4000);
+ best.cnt += 1;
+
+ self.havocbot_attack_time = 0;
+
+ if(checkpvs(self.view_ofs,ad))
+ if(checkpvs(self.view_ofs,best))
+ {
+ // dprint("increasing attack time for this target\n");
+ self.havocbot_attack_time = time + 2;
+ }
+ }
+ }
+}
+
+void havocbot_role_ast_offense()
+{
+ if(self.deadflag != DEAD_NO)
+ {
+ self.havocbot_attack_time = 0;
+ havocbot_ast_reset_role(self);
+ return;
+ }
+
+ // Set the role timeout if necessary
+ if (!self.havocbot_role_timeout)
+ self.havocbot_role_timeout = time + 120;
+
+ if (time > self.havocbot_role_timeout)
+ {
+ havocbot_ast_reset_role(self);
+ return;
+ }
+
+ if(self.havocbot_attack_time>time)
+ return;
+
+ if (self.bot_strategytime < time)
+ {
+ navigation_goalrating_start();
+ havocbot_goalrating_enemyplayers(20000, self.origin, 650);
+ havocbot_goalrating_ast_targets(20000);
+ havocbot_goalrating_items(15000, self.origin, 10000);
+ navigation_goalrating_end();
+
+ self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ }
+}
+
+void havocbot_role_ast_defense()
+{
+ if(self.deadflag != DEAD_NO)
+ {
+ self.havocbot_attack_time = 0;
+ havocbot_ast_reset_role(self);
+ return;
+ }
+
+ // Set the role timeout if necessary
+ if (!self.havocbot_role_timeout)
+ self.havocbot_role_timeout = time + 120;
+
+ if (time > self.havocbot_role_timeout)
+ {
+ havocbot_ast_reset_role(self);
+ return;
+ }
+
+ if(self.havocbot_attack_time>time)
+ return;
+
+ if (self.bot_strategytime < time)
+ {
+ navigation_goalrating_start();
+ havocbot_goalrating_enemyplayers(20000, self.origin, 3000);
+ havocbot_goalrating_ast_targets(20000);
+ havocbot_goalrating_items(15000, self.origin, 10000);
+ navigation_goalrating_end();
+
+ self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ }
+}
+
+void havocbot_role_ast_setrole(entity bot, float role)
+{
+ switch(role)
+ {
+ case HAVOCBOT_AST_ROLE_DEFENSE:
+ bot.havocbot_role = havocbot_role_ast_defense;
+ bot.havocbot_role_flags = HAVOCBOT_AST_ROLE_DEFENSE;
+ bot.havocbot_role_timeout = 0;
+ break;
+ case HAVOCBOT_AST_ROLE_OFFENSE:
+ bot.havocbot_role = havocbot_role_ast_offense;
+ bot.havocbot_role_flags = HAVOCBOT_AST_ROLE_OFFENSE;
+ bot.havocbot_role_timeout = 0;
+ break;
+ }
+}
+
+void havocbot_ast_reset_role(entity bot)
+{
+ if(self.deadflag != DEAD_NO)
+ return;
+
+ if(bot.team==assault_attacker_team)
+ havocbot_role_ast_setrole(bot, HAVOCBOT_AST_ROLE_OFFENSE);
+ else
+ havocbot_role_ast_setrole(bot, HAVOCBOT_AST_ROLE_DEFENSE);
+}
+
+void havocbot_chooserole_ast()
+{
+ havocbot_ast_reset_role(self);
+}
float autocvar_g_arena_point_leadlimit;
float autocvar_g_arena_point_limit;
float autocvar_g_arena_roundbased;
+float autocvar_g_arena_round_timelimit;
float autocvar_g_arena_warmup;
-float autocvar_g_assault;
float autocvar_g_balance_armor_blockpercent;
float autocvar_g_balance_armor_limit;
float autocvar_g_balance_armor_regen;
float autocvar_g_ca_point_limit;
float autocvar_g_ca_round_timelimit;
float autocvar_g_ca_spectate_enemies;
+float autocvar_g_ca_teams;
+float autocvar_g_ca_teams_override;
float autocvar_g_ca_warmup;
float autocvar_g_campaign;
#define autocvar_g_campaign_forceteam cvar("g_campaign_forceteam")
string autocvar_g_forced_team_red;
string autocvar_g_forced_team_yellow;
float autocvar_g_freezetag_frozen_force;
+float autocvar_g_freezetag_frozen_maxtime;
float autocvar_g_freezetag_point_leadlimit;
float autocvar_g_freezetag_point_limit;
float autocvar_g_freezetag_revive_extra_size;
float autocvar_g_freezetag_revive_speed;
float autocvar_g_freezetag_revive_clearspeed;
+float autocvar_g_freezetag_round_timelimit;
+float autocvar_g_freezetag_teams;
+float autocvar_g_freezetag_teams_override;
float autocvar_g_freezetag_warmup;
#define autocvar_g_friendlyfire cvar("g_friendlyfire")
#define autocvar_g_friendlyfire_virtual cvar("g_friendlyfire_virtual")
float autocvar_g_keyhunt_teams_override;
float autocvar_g_lms_campcheck_damage;
float autocvar_g_lms_campcheck_distance;
+float autocvar_g_lms_extra_lives;
float autocvar_g_lms_campcheck_interval;
float autocvar_g_lms_join_anytime;
float autocvar_g_lms_last_join;
float autocvar_g_spawnpoints_auto_move_out_of_solid;
#define autocvar_g_spawnshieldtime cvar("g_spawnshieldtime")
float autocvar_g_spawnsound;
-float autocvar_g_start_delay;
#define autocvar_g_start_weapon_laser cvar("g_start_weapon_laser")
float autocvar_g_tdm_team_spawns;
float autocvar_g_tdm_teams;
float autocvar_g_physical_items;
float autocvar_g_physical_items_damageforcescale;
float autocvar_g_physical_items_reset;
+float autocvar_g_touchexplode_radius;
+float autocvar_g_touchexplode_damage;
+float autocvar_g_touchexplode_edgedamage;
+float autocvar_g_touchexplode_force;
return FALSE;
}
- if(g_freezetag)
- if(e.freezetag_frozen)
- return FALSE;
+ if(e.freezetag_frozen)
+ return FALSE;
// If neither player has ball then don't attack unless the ball is on the
// ground.
FOR_EACH_REALCLIENT(head)
{
- if(head.classname == "player" || g_lms || g_arena || g_ca)
+ if(head.classname == "player" || g_lms || g_arena || head.caplayer == 1)
++activerealplayers;
++realplayers;
}
#include "havocbot.qh"
#include "role_onslaught.qc"
#include "role_keyhunt.qc"
-#include "role_assault.qc"
#include "roles.qc"
void havocbot_ai()
+++ /dev/null
-#define HAVOCBOT_AST_ROLE_NONE 0
-#define HAVOCBOT_AST_ROLE_DEFENSE 2
-#define HAVOCBOT_AST_ROLE_OFFENSE 4
-
-.float havocbot_role_flags;
-.float havocbot_attack_time;
-
-.void() havocbot_role;
-.void() havocbot_previous_role;
-
-void() havocbot_role_ast_defense;
-void() havocbot_role_ast_offense;
-.entity havocbot_ast_target;
-
-void(entity bot) havocbot_ast_reset_role;
-
-void(float ratingscale, vector org, float sradius) havocbot_goalrating_items;
-void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
-
-void havocbot_goalrating_ast_targets(float ratingscale)
-{
- entity ad, best, wp, tod;
- float radius, found, bestvalue;
- vector p;
-
- ad = findchain(classname, "func_assault_destructible");
-
- for (; ad; ad = ad.chain)
- {
- if (ad.target == "")
- continue;
-
- if not(ad.bot_attack)
- continue;
-
- found = FALSE;
- for(tod = world; (tod = find(tod, targetname, ad.target)); )
- {
- if(tod.classname == "target_objective_decrease")
- {
- if(tod.enemy.health > 0 && tod.enemy.health < ASSAULT_VALUE_INACTIVE)
- {
- // dprint(etos(ad),"\n");
- found = TRUE;
- break;
- }
- }
- }
-
- if(!found)
- {
- /// dprint("target not found\n");
- continue;
- }
- /// dprint("target #", etos(ad), " found\n");
-
-
- p = 0.5 * (ad.absmin + ad.absmax);
- // dprint(vtos(ad.origin), " ", vtos(ad.absmin), " ", vtos(ad.absmax),"\n");
- // te_knightspike(p);
- // te_lightning2(world, '0 0 0', p);
-
- // Find and rate waypoints around it
- found = FALSE;
- best = world;
- bestvalue = 99999999999;
- for(radius=0; radius<1500 && !found; radius+=500)
- {
- for(wp=findradius(p, radius); wp; wp=wp.chain)
- {
- if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
- if(wp.classname=="waypoint")
- if(checkpvs(wp.origin, ad))
- {
- found = TRUE;
- if(wp.cnt<bestvalue)
- {
- best = wp;
- bestvalue = wp.cnt;
- }
- }
- }
- }
-
- if(best)
- {
- /// dprint("waypoints around target were found\n");
- // te_lightning2(world, '0 0 0', best.origin);
- // te_knightspike(best.origin);
-
- navigation_routerating(best, ratingscale, 4000);
- best.cnt += 1;
-
- self.havocbot_attack_time = 0;
-
- if(checkpvs(self.view_ofs,ad))
- if(checkpvs(self.view_ofs,best))
- {
- // dprint("increasing attack time for this target\n");
- self.havocbot_attack_time = time + 2;
- }
- }
- }
-}
-
-void havocbot_role_ast_offense()
-{
- if(self.deadflag != DEAD_NO)
- {
- self.havocbot_attack_time = 0;
- havocbot_ast_reset_role(self);
- return;
- }
-
- // Set the role timeout if necessary
- if (!self.havocbot_role_timeout)
- self.havocbot_role_timeout = time + 120;
-
- if (time > self.havocbot_role_timeout)
- {
- havocbot_ast_reset_role(self);
- return;
- }
-
- if(self.havocbot_attack_time>time)
- return;
-
- if (self.bot_strategytime < time)
- {
- navigation_goalrating_start();
- havocbot_goalrating_enemyplayers(20000, self.origin, 650);
- havocbot_goalrating_ast_targets(20000);
- havocbot_goalrating_items(15000, self.origin, 10000);
- navigation_goalrating_end();
-
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
- }
-}
-
-void havocbot_role_ast_defense()
-{
- if(self.deadflag != DEAD_NO)
- {
- self.havocbot_attack_time = 0;
- havocbot_ast_reset_role(self);
- return;
- }
-
- // Set the role timeout if necessary
- if (!self.havocbot_role_timeout)
- self.havocbot_role_timeout = time + 120;
-
- if (time > self.havocbot_role_timeout)
- {
- havocbot_ast_reset_role(self);
- return;
- }
-
- if(self.havocbot_attack_time>time)
- return;
-
- if (self.bot_strategytime < time)
- {
- navigation_goalrating_start();
- havocbot_goalrating_enemyplayers(20000, self.origin, 3000);
- havocbot_goalrating_ast_targets(20000);
- havocbot_goalrating_items(15000, self.origin, 10000);
- navigation_goalrating_end();
-
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
- }
-}
-
-void havocbot_role_ast_setrole(entity bot, float role)
-{
- switch(role)
- {
- case HAVOCBOT_AST_ROLE_DEFENSE:
- bot.havocbot_role = havocbot_role_ast_defense;
- bot.havocbot_role_flags = HAVOCBOT_AST_ROLE_DEFENSE;
- bot.havocbot_role_timeout = 0;
- break;
- case HAVOCBOT_AST_ROLE_OFFENSE:
- bot.havocbot_role = havocbot_role_ast_offense;
- bot.havocbot_role_flags = HAVOCBOT_AST_ROLE_OFFENSE;
- bot.havocbot_role_timeout = 0;
- break;
- }
-}
-
-void havocbot_ast_reset_role(entity bot)
-{
- if(self.deadflag != DEAD_NO)
- return;
-
- if(bot.team==assault_attacker_team)
- havocbot_role_ast_setrole(bot, HAVOCBOT_AST_ROLE_OFFENSE);
- else
- havocbot_role_ast_setrole(bot, HAVOCBOT_AST_ROLE_DEFENSE);
-}
-
-void havocbot_chooserole_ast()
-{
- havocbot_ast_reset_role(self);
-}
havocbot_chooserole_race();
else if (g_onslaught)
havocbot_chooserole_ons();
- else if (g_assault)
- havocbot_chooserole_ast();
else // assume anything else is deathmatch
havocbot_chooserole_dm();
}
WriteByte(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
}
-void Announce(string snd) {
- WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte(MSG_BROADCAST, TE_CSQC_ANNOUNCE);
- WriteString(MSG_BROADCAST, snd);
-}
-
-void AnnounceTo(entity e, string snd) {
- if (clienttype(e) == CLIENTTYPE_REAL)
- {
- msg_entity = e;
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_ANNOUNCE);
- WriteString(MSG_ONE, snd);
- }
-}
-
float ClientData_Send(entity to, float sf)
{
if(to != self.owner)
else
{
float mindist;
- if (arena_roundbased && !g_ca)
+ if (g_arena && arena_roundbased)
mindist = 800;
else
mindist = 100;
WriteEntity(MSG_ONE, self);
}
+ if(g_lms)
+ {
+ // Only if the player cannot play at all
+ if(PlayerScore_Add(self, SP_LMS_RANK, 0) == 666)
+ self.frags = FRAGS_SPECTATOR;
+ else
+ self.frags = FRAGS_LMS_LOSER;
+ }
+ else if((g_race && g_race_qualifying) || g_cts)
+ {
+ if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
+ self.frags = FRAGS_LMS_LOSER;
+ else
+ self.frags = FRAGS_SPECTATOR;
+ }
+ else
+ self.frags = FRAGS_SPECTATOR;
+
MUTATOR_CALLHOOK(MakePlayerObserver);
minstagib_stop_countdown(self);
if not(g_ca) // don't reset teams when moving a ca player to the spectators
self.team = -1; // move this as it is needed to log the player spectating in eventlog
- if(self.killcount != -666) {
- if(g_lms) {
- if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0 && self.lms_spectate_warning != 2)
- Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_NOLIVES, self.netname);
- else
- Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_FORFEIT, self.netname);
- } else { Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_SPECTATE, self.netname); }
+ if(self.killcount != -666)
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_SPECTATE, self.netname);
if(self.just_joined == FALSE) {
LogTeamchange(self.playerid, -1, 4);
self.pauseregen_finished = 0;
self.damageforcescale = 0;
self.death_time = 0;
+ self.respawn_flags = 0;
self.respawn_time = 0;
+ self.stat_respawn_time = 0;
self.alpha = 0;
self.scale = 0;
self.fade_time = 0;
self.punchvector = '0 0 0';
self.oldvelocity = self.velocity;
self.fire_endtime = -1;
-
- if(g_arena)
- {
- if(self.version_mismatch)
- {
- self.frags = FRAGS_SPECTATOR;
- Spawnqueue_Unmark(self);
- Spawnqueue_Remove(self);
- }
- else
- {
- self.frags = FRAGS_LMS_LOSER;
- Spawnqueue_Insert(self);
- }
- }
- else if(g_lms)
- {
- // Only if the player cannot play at all
- if(PlayerScore_Add(self, SP_LMS_RANK, 0) == 666)
- self.frags = FRAGS_SPECTATOR;
- else
- self.frags = FRAGS_LMS_LOSER;
- }
- else if(g_ca)
- {
- if(self.caplayer)
- self.frags = FRAGS_LMS_LOSER;
- else
- self.frags = FRAGS_SPECTATOR;
- }
- else if((g_race && g_race_qualifying) || g_cts)
- {
- if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
- self.frags = FRAGS_LMS_LOSER;
- else
- self.frags = FRAGS_SPECTATOR;
- }
- else
- self.frags = FRAGS_SPECTATOR;
}
.float model_randomizer;
setcolor(self, stof(autocvar_sv_defaultplayercolors));
}
-void PlayerTouchExplode(entity p1, entity p2)
-{
- vector org;
- org = (p1.origin + p2.origin) * 0.5;
- org_z += (p1.mins_z + p2.mins_z) * 0.5;
-
- te_explosion(org);
-
- entity e;
- e = spawn();
- setorigin(e, org);
- RadiusDamage(e, world, g_touchexplode_damage, g_touchexplode_edgedamage, g_touchexplode_radius, world, g_touchexplode_force, DEATH_TOUCHEXPLODE, world);
- remove(e);
-}
-
/*
=============
PutClientInServer
void PutClientInServer (void)
{
if(clienttype(self) == CLIENTTYPE_BOT)
- {
self.classname = "player";
- if(g_ca)
- self.caplayer = 1;
- }
else if(clienttype(self) == CLIENTTYPE_REAL)
{
msg_entity = self;
self.classname = "observer";
}
- if((g_arena && !self.spawned) || (g_ca && !allowed_to_spawn))
- self.classname = "observer";
+ MUTATOR_CALLHOOK(PutClientInServer);
if(gameover)
self.classname = "observer";
- if(self.classname == "player" && (!g_ca || (g_ca && allowed_to_spawn))) {
+ if(self.classname == "player") {
entity spot, oldself;
float j;
}
self.damageforcescale = 2;
self.death_time = 0;
+ self.respawn_flags = 0;
self.respawn_time = 0;
+ self.stat_respawn_time = 0;
self.scale = 0;
self.fade_time = 0;
self.pain_frame = 0;
self.lastteleporttime = time; // prevent insane speeds due to changing origin
self.hud = HUD_NORMAL;
- if(g_arena)
- {
- Spawnqueue_Remove(self);
- Spawnqueue_Mark(self);
- }
- else if(g_ca)
- self.caplayer = 1;
-
self.event_damage = PlayerDamage;
self.bot_attack = TRUE;
//stuffcmd(self, "chase_active 0");
//stuffcmd(self, "set viewsize $tmpviewsize \n");
-
- if(g_assault) {
- if(self.team == assault_attacker_team)
- Send_Notification(NOTIF_TEAM, self, MSG_CENTER, CENTER_ASSAULT_ATTACKING);
- else
- Send_Notification(NOTIF_TEAM, self, MSG_CENTER, CENTER_ASSAULT_DEFENDING);
- }
-
+
target_voicescript_clear(self);
// reset fields the weapons may use
}
else if(self.killindicator_teamchange == -2)
{
- if(g_ca)
- self.caplayer = 0;
if(blockSpectators)
Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
PutObserverInServer();
}
else
SV_ChangeTeam(self.killindicator_teamchange - 1);
+ self.killindicator_teamchange = 0;
}
void ClientKill_Now()
if(clienttype(self.owner) == CLIENTTYPE_REAL)
{
if(self.cnt <= 10)
- AnnounceTo(self.owner, strcat(ftos(self.cnt), ""));
+ { Send_Notification(NOTIF_ONE, self.owner, MSG_ANNCE, Announcer_PickNumber(self.cnt)); }
}
self.nextthink = time + 1;
self.cnt -= 1;
void ClientKill (void)
{
- if (gameover)
- return;
+ if(gameover) return;
+ if(self.player_blocked) return;
+ if(self.freezetag_frozen) return;
- if((g_arena || g_ca) && ((champion && champion.classname == "player" && player_count > 1) || player_count == 1)) // don't allow a kill in this case either
- {
- // do nothing
- }
- else if(self.freezetag_frozen)
- {
- // do nothing
- }
- else
- ClientKill_TeamChange(0);
+ ClientKill_TeamChange(0);
}
void CTS_ClientKill (entity e) // silent version of ClientKill, used when player finishes a CTS run. Useful to prevent cheating by running back to the start line and starting out with more speed
JoinBestTeam(self, FALSE, FALSE); // if the team number is valid, keep it
- if((autocvar_sv_spectate == 1 && !g_lms) || autocvar_g_campaign || self.team_forced < 0) {
+ if((autocvar_sv_spectate == 1) || autocvar_g_campaign || self.team_forced < 0) {
self.classname = "observer";
} else {
if(teamplay)
else
stuffcmd(self, "set _teams_available 0\n");
- if(g_arena || g_ca)
- {
- self.classname = "observer";
- if(g_arena)
- Spawnqueue_Insert(self);
- }
-
attach_entcs();
bot_relinkplayerlist();
if(clienttype(self) == CLIENTTYPE_REAL)
{
- if(autocvar_g_bugrigs || WEPSET_EQ_AW(g_weaponarena_weapons, WEP_TUBA))
- stuffcmd(self, "cl_cmd settemp chase_active 1\n");
- }
-
- if(g_lms)
- {
- if(PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives()) <= 0)
+ if(!autocvar_g_campaign)
{
- PlayerScore_Add(self, SP_LMS_RANK, 666);
- self.frags = FRAGS_SPECTATOR;
+ self.motd_actived_time = -1;
+ Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
}
+
+ if(autocvar_g_bugrigs || WEPSET_EQ_AW(g_weaponarena_weapons, WEP_TUBA))
+ stuffcmd(self, "cl_cmd settemp chase_active 1\n");
}
if(!sv_foginterval && world.fog != "")
CheatInitClient();
- if(!autocvar_g_campaign)
- Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
-
CSQCMODEL_AUTOINIT();
self.model_randomizer = random();
-
- if(clienttype(self) != CLIENTTYPE_REAL)
- return;
-
- sv_notice_join();
-
- MUTATOR_CALLHOOK(ClientConnect);
+
+ if(clienttype(self) == CLIENTTYPE_REAL)
+ sv_notice_join();
+
+ MUTATOR_CALLHOOK(ClientConnect);
}
/*
=============
bot_relinkplayerlist();
- if(g_arena)
- {
- Spawnqueue_Unmark(self);
- Spawnqueue_Remove(self);
- }
-
accuracy_free(self);
ClientData_Detach();
PlayerScore_Detach(self);
limita = limita * limit_mod;
//limitf = limitf * limit_mod;
- if(g_lms && g_ca)
+ if(g_ca)
rot_mod = 0;
if (!g_minstagib && !g_ca && (!g_lms || autocvar_g_lms_regenerate))
self.dmg_inflictor = spectatee.dmg_inflictor;
self.v_angle = spectatee.v_angle;
self.angles = spectatee.v_angle;
- self.stat_respawn_time = spectatee.stat_respawn_time;
if(!self.BUTTON_USE)
self.fixangle = TRUE;
setorigin(self, spectatee.origin);
{
self.respawn_countdown = number - 1;
if(ceil(self.respawn_time - (time + 0.5)) == number) // only say it if it is the same number even in 0.5s; to prevent overlapping sounds
- AnnounceTo(self, strcat(ftos(number), ""));
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, Announcer_PickNumber(number));
}
}
}
void LeaveSpectatorMode()
{
+ if(self.caplayer)
+ return;
if(nJoinAllowed(self))
{
if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0)
if(autocvar_g_campaign)
{ campaign_bots_may_start = 1; }
- else
- { Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD); }
Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
-
+
PutClientInServer();
if(IS_PLAYER(self)) { Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_PLAY, self.netname); }
}
- else if not(g_ca && self.caplayer) { stuffcmd(self, "menu_showteamselect\n"); }
+ else
+ stuffcmd(self, "menu_showteamselect\n");
}
else
{
// Player may not join because g_maxplayers is set
- Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
+ Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_PREVENT);
}
}
return maxclients - totalClients;
float currentlyPlaying = 0;
- FOR_EACH_REALPLAYER(e)
- currentlyPlaying += 1;
+ FOR_EACH_REALCLIENT(e)
+ if(e.classname == "player" || e.caplayer == 1)
+ currentlyPlaying += 1;
if(currentlyPlaying < autocvar_g_maxplayers)
return min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying);
}
}
-.float motd_actived_time; // used for both motd and campaign_message
void PrintWelcomeMessage()
{
- if (self.motd_actived_time == 0) { // is there already a message showing?
+ if(self.motd_actived_time == 0)
+ {
if (autocvar_g_campaign) {
if ((self.classname == "player" && self.BUTTON_INFO) || (self.classname != "player")) {
self.motd_actived_time = time;
Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, campaign_message);
}
} else {
- if ((time - self.jointime > autocvar_welcome_message_time) && self.BUTTON_INFO) {
+ if (self.BUTTON_INFO) {
self.motd_actived_time = time;
Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
}
}
- } else { // showing MOTD or campaign message
+ }
+ else if(self.motd_actived_time > 0) // showing MOTD or campaign message
+ {
if (autocvar_g_campaign) {
if (self.BUTTON_INFO)
self.motd_actived_time = time;
Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
}
} else {
- if ((time - self.jointime) > autocvar_welcome_message_time) {
- if (self.BUTTON_INFO)
- self.motd_actived_time = time;
- else if (time - self.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released
- self.motd_actived_time = 0;
- Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
- }
+ if (self.BUTTON_INFO)
+ self.motd_actived_time = time;
+ else if (time - self.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released
+ self.motd_actived_time = 0;
+ Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
}
}
}
+ else //if(self.motd_actived_time < 0) // just connected, motd is active
+ {
+ if(self.BUTTON_INFO) // BUTTON_INFO hides initial MOTD
+ self.motd_actived_time = -2; // wait until BUTTON_INFO gets released
+ else if(self.motd_actived_time == -2 || IS_PLAYER(self) || time - self.jointime > autocvar_welcome_message_time)
+ {
+ // instanctly hide MOTD
+ self.motd_actived_time = 0;
+ Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
+ }
+ }
}
void ObserverThink()
}
}
}
-
- PrintWelcomeMessage();
}
void SpectatorThink()
PutObserverInServer();
}
- PrintWelcomeMessage();
self.flags |= FL_CLIENT | FL_NOTARGET;
}
MUTATOR_CALLHOOK(PlayerUseKey);
}
-.float touchexplode_time;
-
/*
=============
PlayerPreThink
WarpZone_PlayerPhysics_FixVAngle();
self.stat_game_starttime = game_starttime;
+ self.stat_round_starttime = round_starttime;
self.stat_allow_oldnexbeam = autocvar_g_allow_oldnexbeam;
self.stat_leadlimit = autocvar_leadlimit;
- if(g_arena || (g_ca && !allowed_to_spawn))
- self.stat_respawn_time = 0;
- else
- self.stat_respawn_time = self.respawn_time;
-
if(frametime)
{
// physics frames: update anticheat stuff
self.usekeypressed = self.BUTTON_USE;
}
- PrintWelcomeMessage();
+ if(clienttype(self) == CLIENTTYPE_REAL)
+ PrintWelcomeMessage();
if(self.classname == "player") {
-// if(self.netname == "Wazat")
-// bprint(self.classname, "\n");
CheckRules_Player();
if (self.deadflag != DEAD_NO)
{
- float button_pressed, force_respawn;
if(self.personal && g_race_qualifying)
{
if(time > self.respawn_time)
{
self.respawn_time = time + 1; // only retry once a second
+ self.stat_respawn_time = self.respawn_time;
respawn();
self.impulse = 141;
}
}
else
{
+ float button_pressed;
if(frametime)
player_anim();
button_pressed = (self.BUTTON_ATCK || self.BUTTON_JUMP || self.BUTTON_ATCK2 || self.BUTTON_HOOK || self.BUTTON_USE);
- force_respawn = (g_lms || g_ca || g_cts || autocvar_g_forced_respawn);
+
if (self.deadflag == DEAD_DYING)
{
- if(force_respawn)
+ if(self.respawn_flags & RESPAWN_FORCE)
self.deadflag = DEAD_RESPAWNING;
else if(!button_pressed)
self.deadflag = DEAD_DEAD;
respawn();
}
}
+
ShowRespawnCountdown();
+
+ if(self.respawn_flags & RESPAWN_SILENT)
+ self.stat_respawn_time = 0;
+ else
+ self.stat_respawn_time = self.respawn_time;
}
// if respawning, invert stat_respawn_time to indicate this, the client translates it
return;
}
- // FIXME from now on self.deadflag is always 0 (and self.health is never < 1)
- // so (self.deadflag == DEAD_NO) is always true in the code below
-
- if(g_touchexplode)
- if(time > self.touchexplode_time)
- if(self.classname == "player")
- if(self.deadflag == DEAD_NO)
- if not(IS_INDEPENDENT_PLAYER(self))
- FOR_EACH_PLAYER(other) if(self != other)
- {
- if(time > other.touchexplode_time)
- if(other.deadflag == DEAD_NO)
- if not(IS_INDEPENDENT_PLAYER(other))
- if(boxesoverlap(self.absmin, self.absmax, other.absmin, other.absmax))
- {
- PlayerTouchExplode(self, other);
- self.touchexplode_time = other.touchexplode_time = time + 0.2;
- }
- }
-
- if(g_lms && !self.deadflag && autocvar_g_lms_campcheck_interval)
- {
- vector dist;
-
- // calculate player movement (in 2 dimensions only, so jumping on one spot doesn't count as movement)
- dist = self.prevorigin - self.origin;
- dist_z = 0;
- self.lms_traveled_distance += fabs(vlen(dist));
-
- if((autocvar_g_campaign && !campaign_bots_may_start) || (time < game_starttime))
- {
- self.lms_nextcheck = time + autocvar_g_lms_campcheck_interval*2;
- self.lms_traveled_distance = 0;
- }
-
- if(time > self.lms_nextcheck)
- {
- //sprint(self, "distance: ", ftos(self.lms_traveled_distance), "\n");
- if(self.lms_traveled_distance < autocvar_g_lms_campcheck_distance)
- {
- Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_LMS_CAMPCHECK);
- // FIXME KadaverJack: gibbing player here causes playermodel to bounce around, instead of eye.md3
- // I wasn't able to find out WHY that happens, so I put a workaround in place that shall prevent players from being gibbed :(
- Damage(self, self, self, bound(0, autocvar_g_lms_campcheck_damage, self.health + self.armorvalue * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP, self.origin, '0 0 0');
- }
- self.lms_nextcheck = time + autocvar_g_lms_campcheck_interval;
- self.lms_traveled_distance = 0;
- }
- }
self.prevorigin = self.origin;
else if(timeleft <= 10)
{
if(timeleft != self.idlekick_lasttimeleft)
- AnnounceTo(self, ftos(timeleft));
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, Announcer_PickNumber(timeleft));
self.idlekick_lasttimeleft = timeleft;
}
}
return;
self.impulse = 0;
+ // forbid impulses when not in round time
+ if(round_handler_IsActive() && !round_handler_IsRoundStarted())
+ return;
+
if (timeout_status == TIMEOUT_ACTIVE) //don't allow any impulses while the game is paused
return;
mjumpheight = autocvar_sv_jumpvelocity;
if (self.waterlevel >= WATERLEVEL_SWIMMING)
{
- if (self.watertype == CONTENT_WATER)
- self.velocity_z = 200;
- else if (self.watertype == CONTENT_SLIME)
- self.velocity_z = 80;
- else
- self.velocity_z = 50;
-
+ self.velocity_z = self.stat_sv_maxspeed * 0.7;
return;
}
rigvel_z -= frametime * autocvar_sv_gravity; // 4x gravity plays better
rigvel_xy = vec2(rigvel);
- if(g_bugrigs_planar_movement_car_jumping && !g_touchexplode) // touchexplode is a better way to handle collisions
+ if(g_bugrigs_planar_movement_car_jumping)
mt = MOVE_NORMAL;
else
mt = MOVE_NOMONSTERS;
}
void ClientKill_Now_TeamChange();
-void freezetag_CheckWinner();
void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
{
float valid_damage_for_weaponstats;
float excess;
- if((g_arena && numspawned < 2) || (g_ca && allowed_to_spawn) && !inWarmupStage)
- return;
-
dh = max(self.health, 0);
da = max(self.armorvalue, 0);
}
}
- if(!g_freezetag)
- {
- // become fully visible
- self.alpha = default_player_alpha;
- // throw a weapon
- SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon);
- }
-
// print an obituary message
Obituary (attacker, inflictor, self, deathtype);
race_PreDie();
if(accuracy_isgooddamage(attacker, self))
attacker.accuracy.(accuracy_frags[w-1]) += 1;
- if(deathtype == DEATH_HURTTRIGGER && g_freezetag)
- {
- PutClientInServer();
- count_alive_players(); // re-count players
- freezetag_CheckWinner();
- return;
- }
-
frag_attacker = attacker;
frag_inflictor = inflictor;
frag_target = self;
+ frag_deathtype = deathtype;
MUTATOR_CALLHOOK(PlayerDies);
+
weapon_action(self.weapon, WR_PLAYERDEATH);
RemoveGrapplingHook(self);
//WriteAngle (MSG_ONE, 80);
}
- if(defer_ClientKill_Now_TeamChange) // TODO does this work with FreezeTag?
- ClientKill_Now_TeamChange();
-
- if(g_arena)
- Spawnqueue_Unmark(self);
+ if(defer_ClientKill_Now_TeamChange)
+ ClientKill_Now_TeamChange(); // can turn player into spectator
- if(g_freezetag)
+ // player could have been miraculously resuscitated ;)
+ // e.g. players in freezetag get frozen, they don't really die
+ if(self.health >= 1 || self.classname != "player")
return;
// when we get here, player actually dies
- // clear waypoints (do this AFTER FreezeTag)
+
+ // clear waypoints
WaypointSprite_PlayerDead();
+ // throw a weapon
+ SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon);
+ // become fully visible
+ self.alpha = default_player_alpha;
// make the corpse upright (not tilted)
self.angles_x = 0;
self.angles_z = 0;
self.respawn_countdown = 10; // first number to count down from is 10
else
self.respawn_countdown = -1; // do not count down
+
+ if(g_lms || g_cts || autocvar_g_forced_respawn)
+ self.respawn_flags = self.respawn_flags | RESPAWN_FORCE;
+
self.death_time = time;
if (random() < 0.5)
animdecide_setstate(self, self.anim_state | ANIMSTATE_DEAD1, TRUE);
return 0;
if (g_weaponarena)
return 0;
- if (g_lms)
- return 0;
- if (g_ca)
- return 0;
if (g_cts)
return 0;
if (g_nexball && w == WEP_GRENADE_LAUNCHER)
Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_WEAPON_DROP, a, w);
}
-// Bringed back weapon frame
+float forbidWeaponUse()
+{
+ if(time < game_starttime && !autocvar_sv_ready_restart_after_countdown)
+ return 1;
+ if(round_handler_IsActive() && !round_handler_IsRoundStarted())
+ return 1;
+ if(self.player_blocked)
+ return 1;
+ if(self.freezetag_frozen)
+ return 1;
+ return 0;
+}
+
void W_WeaponFrame()
{
vector fo, ri, up;
if (frametime)
self.weapon_frametime = frametime;
- if(((arena_roundbased || g_ca || g_freezetag) && time < warmup) || ((time < game_starttime) && !autocvar_sv_ready_restart_after_countdown))
- return;
-
- if(self.freezetag_frozen == 1)
- return;
-
if (!self.weaponentity || self.health < 1)
return; // Dead player can't use weapons and injure impulse commands
+ if(forbidWeaponUse())
+ if(self.weaponentity.state != WS_CLEAR)
+ {
+ w_ready();
+ return;
+ }
+
if(!self.switchweapon)
{
self.weapon = 0;
{
if(nJoinAllowed(self))
{
- if(g_ca) { self.caplayer = 1; }
if(autocvar_g_campaign) { campaign_bots_may_start = 1; }
-
+
self.classname = "player";
PlayerScore_Clear(self);
- Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_PLAY, self.netname);
PutClientInServer();
else
{
//player may not join because of g_maxplayers is set
- Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
+ Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_PREVENT);
}
}
}
{
if(!readyrestart_happened || autocvar_sv_ready_restart_repeatable)
{
+ if(time < game_starttime) // game is already restarting
+ return;
if (self.ready) // toggle
{
self.ready = FALSE;
if(self.classname == "player" && autocvar_sv_spectate == 1)
ClientKill_TeamChange(-2); // observe
-
+
// in CA, allow a dead player to move to spectators (without that, caplayer!=0 will be moved back to the player list)
// note: if arena game mode is ever done properly, this needs to be removed.
- if(g_ca && self.caplayer && (self.classname == "spectator" || self.classname == "observer"))
+ if(self.caplayer && (self.classname == "spectator" || self.classname == "observer"))
{
sprint(self, "WARNING: you will spectate in the next round.\n");
self.caplayer = 0;
Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_TIMEOUT_ENDING, timeout_time);
if(timeout_time == autocvar_sv_timeout_resumetime) // play a warning sound when only <sv_timeout_resumetime> seconds are left
- Announce("prepareforbattle");
+ Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_PREPARE);
self.nextthink = time + TIMEOUT_SLOWMO_VALUE; // think again in one second
timeout_time -= 1; // decrease the time counter
timeout_handler.think = timeout_handler_think;
timeout_handler.nextthink = time; // always let the entity think asap
- Announce("timeoutcalled");
+ Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_TIMEOUT);
}
}
else { print_to(caller, "^1Timeouts are not allowed to be called, enable them with sv_timeout 1.\n"); }
if(vote_caller) { vote_caller.vote_waittime = 0; } // people like your votes, you don't need to wait to vote again
VoteReset();
- Announce("voteaccept");
+ Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_ACCEPT);
}
void VoteReject()
{
bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ", vote_called_display, "^2 was rejected\n");
VoteReset();
- Announce("votefail");
+ Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_FAIL);
}
void VoteTimeout()
{
bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ", vote_called_display, "^2 timed out\n");
VoteReset();
- Announce("votefail");
+ Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_FAIL);
}
void VoteSpam(float notvoters, float mincount, string result)
// Game logic for warmup
// =======================
+// Resets the state of all clients, items, weapons, waypoints, ... of the map.
+void reset_map(float dorespawn)
+{
+ entity oldself;
+ oldself = self;
+
+ if(time <= game_starttime && round_handler_IsActive())
+ round_handler_Reset(game_starttime);
+
+ if(g_race || g_cts)
+ race_ReadyRestart();
+ else MUTATOR_CALLHOOK(reset_map_global);
+
+ lms_lowest_lives = 999;
+ lms_next_place = player_count;
+
+ for(self = world; (self = nextent(self)); )
+ if(clienttype(self) == CLIENTTYPE_NOTACLIENT)
+ {
+ if(self.reset)
+ {
+ self.reset();
+ continue;
+ }
+
+ if(self.team_saved)
+ self.team = self.team_saved;
+
+ if(self.flags & FL_PROJECTILE) // remove any projectiles left
+ remove(self);
+ }
+
+ // Waypoints and assault start come LAST
+ for(self = world; (self = nextent(self)); )
+ if(clienttype(self) == CLIENTTYPE_NOTACLIENT)
+ {
+ if(self.reset2)
+ {
+ self.reset2();
+ continue;
+ }
+ }
+
+ // Moving the player reset code here since the player-reset depends
+ // on spawnpoint entities which have to be reset first --blub
+ if(dorespawn)
+ if(!MUTATOR_CALLHOOK(reset_map_players))
+ FOR_EACH_CLIENT(self) // reset all players
+ {
+ /*
+ only reset players if a restart countdown is active
+ this can either be due to cvar sv_ready_restart_after_countdown having set
+ restart_mapalreadyrestarted to 1 after the countdown ended or when
+ sv_ready_restart_after_countdown is not used and countdown is still running
+ */
+ if (restart_mapalreadyrestarted || (time < game_starttime))
+ {
+ //NEW: changed behaviour so that it prevents that previous spectators/observers suddenly spawn as players
+ if (IS_PLAYER(self)) {
+ //PlayerScore_Clear(self);
+ if(g_lms)
+ PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives());
+ self.killcount = 0;
+ //stop the player from moving so that he stands still once he gets respawned
+ self.velocity = '0 0 0';
+ self.avelocity = '0 0 0';
+ self.movement = '0 0 0';
+ PutClientInServer();
+ }
+ }
+ }
+
+ if(g_keyhunt)
+ kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round + (game_starttime - time), kh_StartRound);
+
+ self = oldself;
+}
+
// Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown is set)
void ReadyRestart_think()
{
checkrules_suddendeathend = checkrules_overtimesadded = checkrules_suddendeathwarning = 0;
readyrestart_happened = 1;
- game_starttime = time;
- if(!g_ca && !g_arena) { game_starttime += RESTART_COUNTDOWN; }
+ game_starttime = time + RESTART_COUNTDOWN;
- // clear alivetime
+ // clear player attributes
FOR_EACH_CLIENT(tmp_player)
{
tmp_player.alivetime = 0;
+ tmp_player.killcount = 0;
PlayerStats_Event(tmp_player, PLAYERSTATS_ALIVETIME, -PlayerStats_Event(tmp_player, PLAYERSTATS_ALIVETIME, 0));
}
inWarmupStage = 0; // once the game is restarted the game is in match stage
// reset the .ready status of all players (also spectators)
- FOR_EACH_CLIENTSLOT(tmp_player) { tmp_player.ready = 0; }
+ FOR_EACH_REALCLIENT(tmp_player) { tmp_player.ready = 0; }
readycount = 0;
Nagger_ReadyCounted(); // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
// lock teams with lockonrestart
- if(autocvar_teamplay_lockonrestart && teamplay)
+ if(autocvar_teamplay_lockonrestart && teamplay)
{
lockteams = 1;
bprint("^1The teams are now locked.\n");
}
//initiate the restart-countdown-announcer entity
- if(autocvar_sv_ready_restart_after_countdown && !g_ca && !g_arena)
+ if(autocvar_sv_ready_restart_after_countdown)
{
restart_timer = spawn();
restart_timer.think = ReadyRestart_think;
float ready_needed_factor, ready_needed_count;
float t_ready = 0, t_players = 0;
- FOR_EACH_REALPLAYER(tmp_player)
+ FOR_EACH_REALCLIENT(tmp_player)
{
- ++t_players;
- if(tmp_player.ready) { ++t_ready; }
+ if(IS_PLAYER(tmp_player) || tmp_player.caplayer == 1)
+ {
+ ++t_players;
+ if(tmp_player.ready) { ++t_ready; }
+ }
}
readycount = t_ready;
if(accepted > 0)
{
- string reason = ((argc > next_token) ? substring(vote_command, argv_start_index(next_token), argv_end_index(-1) - argv_start_index(next_token)) : "No reason provided");
+ string reason = ((argc > next_token) ? substring(vote_command, argv_start_index(next_token), strlen(vote_command) - argv_start_index(next_token)) : "No reason provided");
string command_arguments;
if(first_command == "kickban")
}
FOR_EACH_REALCLIENT(tmp_player) { ++tmp_playercount; }
- if(tmp_playercount > 1) { Announce("votecall"); } // don't announce a "vote now" sound if player is alone
+ if(tmp_playercount > 1) { Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_CALL); } // don't announce a "vote now" sound if player is alone
bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2 calls a vote for ", vote_called_display, "\n");
if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display)); }
float readyrestart_happened; // keeps track of whether a restart has already happened
float restart_mapalreadyrestarted; // bool, indicates whether reset_map() was already executed
.float ready; // flag for if a player is ready
+void reset_map(float dorespawn);
void ReadyCount();
\ No newline at end of file
float DEAD_RESPAWNABLE = 3;
float DEAD_RESPAWNING = 4;
+float RESPAWN_FORCE = 1;
+float RESPAWN_SILENT = 2;
+
float DAMAGE_NO = 0;
float DAMAGE_YES = 1;
float DAMAGE_AIM = 2;
float player_count;
float currentbots;
float bots_would_leave;
-float lms_lowest_lives;
-float lms_next_place;
-float LMS_NewPlayerLives();
void UpdateFrags(entity player, float f);
.float totalfrags;
//.float cnt2;
.float play_time;
+.float respawn_flags;
.float respawn_time;
.float death_time;
.float fade_time;
.float winning;
.float jointime; // time of joining
.float alivetime; // time of being alive
+.float motd_actived_time; // used for both motd and campaign_message
float nJoinAllowed(entity ignore);
-#define PREVENT_JOIN_TEXT "^1You may not join the game at this time.\n\nThe player limit reached maximum capacity."
.float spawnshieldtime;
.float cvar_cl_allow_uidtracking;
.string stored_netname;
-void Announce(string snd);
-void AnnounceTo(entity e, string snd);
-
.float version_nagtime;
#define NUM_JUMPPADSUSED 3
string cvar_purechanges;
float cvar_purechanges_count;
-float game_starttime; //point in time when the countdown is over
+float game_starttime; //point in time when the countdown to game start is over
+float round_starttime; //point in time when the countdown to round start is over
.float stat_game_starttime;
+.float stat_round_starttime;
.float stat_sv_airaccel_qw;
.float stat_sv_airstrafeaccel_qw;
.void (float act_state) setactive;
.entity realowner;
-float allowed_to_spawn; // boolean variable used by the clan arena code to determine if a player can spawn (after the round has ended)
-
float serverflags;
.float team_forced; // can be a team number to force a team, or 0 for default action, or -1 for forced spectator
.float player_blocked;
.float freezetag_frozen;
-.float freezetag_revive_progress;
.entity muzzle_flash;
.float misc_bulletcounter; // replaces uzi & hlac bullet counter.
PlayerScore_Add(targ, SP_DEATHS, 1);
- if(g_arena || g_ca)
- if(autocvar_g_arena_roundbased)
- return;
-
if(targ != attacker) // not for suicides
if(g_weaponarena_random)
{
else
{
self = oldself;
- if(g_lms)
- {
- // remove a life
- float tl;
- tl = PlayerScore_Add(targ, SP_LMS_LIVES, -1);
- if(tl < lms_lowest_lives)
- lms_lowest_lives = tl;
- if(tl <= 0)
- {
- if(!lms_next_place)
- lms_next_place = player_count;
- else
- lms_next_place = min(lms_next_place, player_count);
- PlayerScore_Add(targ, SP_LMS_RANK, lms_next_place); // won't ever spawn again
- --lms_next_place;
- }
- f = 0;
- }
}
attacker.totalfrags += f;
string deathlocation = (autocvar_notification_server_allows_location ? NearestLocation(targ.death_origin) : "");
#ifdef NOTIFICATIONS_DEBUG
- dprint(
+ Debug_Notification(
sprintf(
"Obituary(%s, %s, %s, %s = %d);\n",
attacker.netname,
Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAG, targ.netname);
Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAGGED, attacker.netname);
- Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(targ.team, INFO_DEATH_TEAMKILL_), targ.netname, attacker.netname, targ.killcount);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(targ.team, INFO_DEATH_TEAMKILL_), targ.netname, attacker.netname, deathlocation, targ.killcount);
// In this case, the death message will ALWAYS be "foo was betrayed by bar"
// No need for specific death/weapon messages...
#define SPREE_ITEM(counta,countb,center,normal,gentle) \
case counta: \
{ \
- AnnounceTo(attacker, strcat(#countb, "kills")); \
+ Send_Notification(NOTIF_ONE, attacker, MSG_ANNCE, ANNCE_KILLSTREAK_##countb); \
PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
break; \
}
if(PlayerScore_Add(targ, SP_SCORE, 0) == -5)
{
- AnnounceTo(targ, "botlike");
+ Send_Notification(NOTIF_ONE, targ, MSG_ANNCE, ANNCE_ACHIEVEMENT_BOTLIKE);
PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
}
}
}
}
- if(targ.classname == "player")
- if(attacker.classname == "player")
- if(attacker != targ)
- {
- targ.lms_traveled_distance = autocvar_g_lms_campcheck_distance;
- attacker.lms_traveled_distance = autocvar_g_lms_campcheck_distance;
- }
-
if(targ.classname == "player")
if (g_minstagib)
{
error("Owner lost the hook!\n");
return;
}
- if(LostMovetypeFollow(self) || intermission_running)
+ if(LostMovetypeFollow(self) || intermission_running || (round_handler_IsActive() && !round_handler_IsRoundStarted()))
{
RemoveGrapplingHook(self.realowner);
return;
float s;
vector vs;
- if((arena_roundbased && time < warmup) || (time < game_starttime))
- return;
-
- if(self.freezetag_frozen)
- return;
-
- if(self.vehicle)
- return;
+ if(forbidWeaponUse()) return;
+ if(self.vehicle) return;
makevectors(self.v_angle);
BADCVAR("g_arena");
BADCVAR("g_assault");
BADCVAR("g_ca");
+ BADCVAR("g_ca_teams");
BADCVAR("g_ctf");
BADCVAR("g_cts");
BADCVAR("g_dm");
BADCVAR("g_domination");
BADCVAR("g_domination_default_teams");
BADCVAR("g_freezetag");
+ BADCVAR("g_freezetag_teams");
BADCVAR("g_keepaway");
BADCVAR("g_keyhunt");
BADCVAR("g_keyhunt_teams");
- BADCVAR("g_keyhunt_teams");
BADCVAR("g_lms");
BADCVAR("g_nexball");
BADCVAR("g_onslaught");
BADCVAR("g_balance_teams_scorefactor");
BADCVAR("g_ban_sync_trusted_servers");
BADCVAR("g_ban_sync_uri");
+ BADCVAR("g_ca_teams_override");
BADCVAR("g_ctf_ignore_frags");
BADCVAR("g_domination_point_limit");
+ BADCVAR("g_freezetag_teams_override");
BADCVAR("g_friendlyfire");
BADCVAR("g_fullbrightitems");
BADCVAR("g_fullbrightplayers");
compressShortVector_init();
- allowed_to_spawn = TRUE;
-
entity head;
head = nextent(world);
maxclients = 0;
addstat(STAT_SWITCHWEAPON, AS_INT, switchweapon);
addstat(STAT_SWITCHINGWEAPON, AS_INT, switchingweapon);
addstat(STAT_GAMESTARTTIME, AS_FLOAT, stat_game_starttime);
+ addstat(STAT_ROUNDSTARTTIME, AS_FLOAT, stat_round_starttime);
addstat(STAT_ALLOW_OLDNEXBEAM, AS_INT, stat_allow_oldnexbeam);
Nagger_Init();
addstat(STAT_HAGAR_LOAD, AS_INT, hagar_load);
- if(g_ca || g_freezetag)
- {
- addstat(STAT_REDALIVE, AS_INT, redalive_stat);
- addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat);
- addstat(STAT_YELLOWALIVE, AS_INT, yellowalive_stat);
- addstat(STAT_PINKALIVE, AS_INT, pinkalive_stat);
- }
- if(g_freezetag)
- {
- addstat(STAT_FROZEN, AS_INT, freezetag_frozen);
- addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress);
- }
-
// g_movementspeed hack
addstat(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW, AS_FLOAT, stat_sv_airspeedlimit_nonqw);
addstat(STAT_MOVEVARS_MAXSPEED, AS_FLOAT, stat_sv_maxspeed);
&& ((self.autoscreenshot > 0) && (time > self.autoscreenshot)) )
{
self.autoscreenshot = -1;
- if(clienttype(self) == CLIENTTYPE_REAL) { stuffcmd(self, sprintf("\nscreenshot screenshots/autoscreenshot/%s-%s.jpg; echo \"^5A screenshot has been taken at request of the server.\"", GetMapname(), strftime(FALSE, "%s"))); }
+ if(clienttype(self) == CLIENTTYPE_REAL) { stuffcmd(self, sprintf("\nscreenshot screenshots/autoscreenshot/%s-%s.jpg; echo \"^5A screenshot has been taken at request of the server.\"\n", GetMapname(), strftime(FALSE, "%s"))); }
return;
}
{
s = strcat(":player:see-labels:", GetPlayerScoreString(other, 0), ":");
s = strcat(s, ftos(rint(time - other.jointime)), ":");
- if(other.classname == "player" || g_arena || g_ca || g_lms)
+ if(other.classname == "player" || g_arena || other.caplayer == 1 || g_lms)
s = strcat(s, ftos(other.team), ":");
else
s = strcat(s, "spectator:");
PlayerStats_AddGlobalInfo(e);
PlayerStats_Shutdown();
WeaponStats_Shutdown();
-
+
Kill_Notification(NOTIF_ALL, world, MSG_CENTER, 0); // kill all centerprints now
if(autocvar_sv_eventlog)
tl += autocvar_timelimit_overtime;
cvar_set("timelimit", ftos(tl));
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime);
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime * 60);
}
float GetWinningCode(float fraglimitreached, float equality)
return WINNING_NO;
}
-float LMS_NewPlayerLives()
-{
- float fl;
- fl = autocvar_fraglimit;
- if(fl == 0)
- fl = 999;
-
- // first player has left the game for dying too much? Nobody else can get in.
- if(lms_lowest_lives < 1)
- return 0;
-
- if(!autocvar_g_lms_join_anytime)
- if(lms_lowest_lives < fl - autocvar_g_lms_last_join)
- return 0;
-
- return bound(1, lms_lowest_lives, fl);
-}
-
// Assault winning condition: If the attackers triggered a round end (by fulfilling all objectives)
// they win. Otherwise the defending team wins once the timelimit passes.
void assault_new_round();
if (limit)
if (leaderfrags == limit - 1)
- Announce("1fragleft");
+ Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_REMAINING_FRAG_1);
else if (leaderfrags == limit - 2)
- Announce("2fragsleft");
+ Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_REMAINING_FRAG_2);
else if (leaderfrags == limit - 3)
- Announce("3fragsleft");
+ Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_REMAINING_FRAG_3);
}
}
s = cvar_string("g_weaponarena");
if (s == "0" || s == "")
{
- if(g_lms || g_ca)
+ if(g_ca)
s = "most";
}
g_pinata = 0; // incompatible
g_weapon_stay = 0; // incompatible
WEPSET_COPY_AA(start_weapons, g_weaponarena_weapons);
- if(!(g_lms || g_ca))
+ if(!g_ca)
start_items |= IT_UNLIMITED_AMMO;
}
else if (g_minstagib)
}
else
{
- if(g_lms || g_ca)
+ if(g_ca)
{
start_ammo_shells = cvar("g_lms_start_ammo_shells");
start_ammo_nails = cvar("g_lms_start_ammo_nails");
}
}
- if (g_lms || g_ca)
+ if (g_ca)
{
start_health = cvar("g_lms_start_health");
start_armorvalue = cvar("g_lms_start_armor");
float g_bugrigs_speed_pow;
float g_bugrigs_steer;
-float g_touchexplode;
-float g_touchexplode_radius;
-float g_touchexplode_damage;
-float g_touchexplode_edgedamage;
-float g_touchexplode_force;
-
float sv_autotaunt;
float sv_taunt;
MUTATOR_ADD(mutator_spawn_near_teammate);
if(cvar("g_physical_items"))
MUTATOR_ADD(mutator_physical_items);
+ if(cvar("g_touchexplode"))
+ MUTATOR_ADD(mutator_touchexplode);
if(!g_minstagib)
{
if(cvar("g_invincible_projectiles"))
g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
g_bugrigs_steer = cvar("g_bugrigs_steer");
- g_touchexplode = cvar("g_touchexplode");
- g_touchexplode_radius = cvar("g_touchexplode_radius");
- g_touchexplode_damage = cvar("g_touchexplode_damage");
- g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
- g_touchexplode_force = cvar("g_touchexplode_force");
-
sv_clones = cvar("sv_clones");
sv_foginterval = cvar("sv_foginterval");
g_cloaked = cvar("g_cloaked");
if(!g_weapon_stay)
g_weapon_stay = cvar("g_weapon_stay");
- if not(inWarmupStage && !g_ca)
- game_starttime = cvar("g_start_delay");
+ if not(inWarmupStage)
+ game_starttime = time + cvar("g_start_delay");
readplayerstartcvars();
}
MUTATOR_HOOKABLE(MakePlayerObserver);
// called when a player becomes observer, after shared setup
+MUTATOR_HOOKABLE(PutClientInServer);
+ entity self; // client wanting to spawn
+
MUTATOR_HOOKABLE(PlayerSpawn);
entity spawn_spot; // spot that was used, or world
// called when a player spawns as player, after shared setup, before his weapon is chosen (so items may be changed in here)
+MUTATOR_HOOKABLE(reset_map_global);
+ // called in reset_map
+
+MUTATOR_HOOKABLE(reset_map_players);
+ // called in reset_map
+
+MUTATOR_HOOKABLE(ForbidPlayerScore_Clear);
+ // returns 1 if clearing player score shall not be allowed
+
MUTATOR_HOOKABLE(ClientDisconnect);
// called when a player disconnects
entity frag_inflictor;
entity frag_attacker;
entity frag_target; // same as self
+ float frag_deathtype;
MUTATOR_HOOKABLE(GiveFragsForKill);
// called when someone was fragged by "self", and is expected to change frag_score to adjust scoring for the kill
// INPUT
entity self; // the player who pressed impulse 33
+MUTATOR_HOOKABLE(VehicleSpawn);
+ // called when a vehicle initializes
+ // return TRUE to remove the vehicle
+
MUTATOR_HOOKABLE(VehicleEnter);
// called when a player enters a vehicle
// allows mutators to set special settings in this event
--- /dev/null
+.float spawned;
+float maxspawned;
+float numspawned;
+.entity spawnqueue_next;
+.entity spawnqueue_prev;
+.float spawnqueue_in;
+entity spawnqueue_first;
+entity spawnqueue_last;
+
+void Spawnqueue_Insert(entity e)
+{
+ if(e.spawnqueue_in)
+ return;
+ dprint(strcat("Into queue: ", e.netname, "\n"));
+ e.spawnqueue_in = TRUE;
+ e.spawnqueue_prev = spawnqueue_last;
+ e.spawnqueue_next = world;
+ if(spawnqueue_last)
+ spawnqueue_last.spawnqueue_next = e;
+ spawnqueue_last = e;
+ if(!spawnqueue_first)
+ spawnqueue_first = e;
+}
+
+void Spawnqueue_Remove(entity e)
+{
+ if(!e.spawnqueue_in)
+ return;
+ dprint(strcat("Out of queue: ", e.netname, "\n"));
+ e.spawnqueue_in = FALSE;
+ if(e == spawnqueue_first)
+ spawnqueue_first = e.spawnqueue_next;
+ if(e == spawnqueue_last)
+ spawnqueue_last = e.spawnqueue_prev;
+ if(e.spawnqueue_prev)
+ e.spawnqueue_prev.spawnqueue_next = e.spawnqueue_next;
+ if(e.spawnqueue_next)
+ e.spawnqueue_next.spawnqueue_prev = e.spawnqueue_prev;
+ e.spawnqueue_next = world;
+ e.spawnqueue_prev = world;
+}
+
+void Spawnqueue_Unmark(entity e)
+{
+ if(!e.spawned)
+ return;
+ e.spawned = FALSE;
+ numspawned = numspawned - 1;
+}
+
+void Spawnqueue_Mark(entity e)
+{
+ if(e.spawned)
+ return;
+ e.spawned = TRUE;
+ numspawned = numspawned + 1;
+}
+
+float Arena_CheckWinner()
+{
+ entity e;
+
+ if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_OVER);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_OVER);
+ round_handler_Init(5, autocvar_g_arena_warmup, autocvar_g_arena_round_timelimit);
+ return 1;
+ }
+
+ if(numspawned > 1)
+ return 0;
+
+ entity champion;
+ champion = world;
+ FOR_EACH_CLIENT(e)
+ {
+ if(e.spawned && IS_PLAYER(e))
+ champion = e;
+ }
+
+ if(champion)
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_PLAYER_WIN, champion.netname);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_PLAYER_WIN, champion.netname);
+ UpdateFrags(champion, +1);
+ }
+ else
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_TIED);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_TIED);
+ }
+ round_handler_Init(5, autocvar_g_arena_warmup, autocvar_g_arena_round_timelimit);
+ return 1;
+}
+
+void Arena_AddChallengers()
+{
+ entity e;
+ if(time < 2) // don't force players to spawn so early
+ return;
+ e = self;
+ while(numspawned < maxspawned && spawnqueue_first)
+ {
+ self = spawnqueue_first;
+
+ bprint ("^4", self.netname, "^4 is the next challenger\n");
+
+ Spawnqueue_Remove(self);
+ Spawnqueue_Mark(self);
+
+ self.classname = "player";
+ PutClientInServer();
+ }
+ self = e;
+}
+
+float prev_numspawned;
+float Arena_CheckPlayers()
+{
+ Arena_AddChallengers();
+
+ if(numspawned >= 2)
+ {
+ if(prev_numspawned > 0)
+ Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_MISSING_PLAYERS);
+ prev_numspawned = -1;
+ return 1;
+ }
+
+ if(prev_numspawned != numspawned && numspawned == 1)
+ {
+ if(maxspawned - numspawned > 0)
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_MISSING_PLAYERS, maxspawned - numspawned);
+ prev_numspawned = numspawned;
+ }
+
+ return 0;
+}
+
+void Arena_RoundStart()
+{
+ entity e;
+ FOR_EACH_PLAYER(e)
+ e.player_blocked = 0;
+}
+
+MUTATOR_HOOKFUNCTION(arena_ClientDisconnect)
+{
+ Spawnqueue_Unmark(self);
+ Spawnqueue_Remove(self);
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(arena_reset_map_players)
+{
+ FOR_EACH_CLIENT(self)
+ {
+ if(self.spawned)
+ {
+ PutClientInServer();
+ self.player_blocked = 1;
+ }
+ else
+ PutObserverInServer();
+ }
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(arena_MakePlayerObserver)
+{
+ if(self.version_mismatch)
+ {
+ self.frags = FRAGS_SPECTATOR;
+ Spawnqueue_Unmark(self);
+ Spawnqueue_Remove(self);
+ }
+ else
+ {
+ self.frags = FRAGS_LMS_LOSER;
+ Spawnqueue_Insert(self);
+ }
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(arena_PutClientInServer)
+{
+ if(!self.spawned)
+ self.classname = "observer";
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(arena_ClientConnect)
+{
+ self.classname = "observer";
+ Spawnqueue_Insert(self);
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(arena_PlayerSpawn)
+{
+ Spawnqueue_Remove(self);
+ Spawnqueue_Mark(self);
+ if(arena_roundbased)
+ self.player_blocked = 1;
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(arena_ForbidPlayerScore_Clear)
+{
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(arena_GiveFragsForKill)
+{
+ if(arena_roundbased)
+ frag_score = 0; // score will be given to the champion when the round ends
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(arena_PlayerDies)
+{
+ // put dead players in the spawn queue
+ if(arena_roundbased)
+ self.respawn_flags = (RESPAWN_FORCE | RESPAWN_SILENT);
+ else
+ self.respawn_flags = RESPAWN_SILENT;
+ Spawnqueue_Unmark(self);
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(arena_SV_StartFrame)
+{
+ if(gameover) return 1;
+ if(time <= game_starttime || !arena_roundbased)
+ Arena_AddChallengers();
+ return 1;
+}
+
+void arena_Initialize()
+{
+ maxspawned = max(2, autocvar_g_arena_maxspawned);
+ arena_roundbased = autocvar_g_arena_roundbased;
+ if(arena_roundbased)
+ {
+ round_handler_Spawn(Arena_CheckPlayers, Arena_CheckWinner, Arena_RoundStart);
+ round_handler_Init(5, autocvar_g_arena_warmup, autocvar_g_arena_round_timelimit);
+ }
+}
+
+MUTATOR_DEFINITION(gamemode_arena)
+{
+ MUTATOR_HOOK(ClientDisconnect, arena_ClientDisconnect, CBC_ORDER_ANY);
+ MUTATOR_HOOK(reset_map_players, arena_reset_map_players, CBC_ORDER_ANY);
+ MUTATOR_HOOK(MakePlayerObserver, arena_MakePlayerObserver, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PutClientInServer, arena_PutClientInServer, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ClientConnect, arena_ClientConnect, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerSpawn, arena_PlayerSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ForbidPlayerScore_Clear, arena_ForbidPlayerScore_Clear, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GiveFragsForKill, arena_GiveFragsForKill, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerDies, arena_PlayerDies, CBC_ORDER_ANY);
+ MUTATOR_HOOK(SV_StartFrame, arena_SV_StartFrame, CBC_ORDER_ANY);
+
+ MUTATOR_ONADD
+ {
+ if(time > 1) // game loads at time 1
+ error("This is a game type and it cannot be added at runtime.");
+ arena_Initialize();
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ print("This is a game type and it cannot be removed at runtime.");
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+// should be removed in the future, as other code should not have to care
+float arena_roundbased;
--- /dev/null
+// random functions
+void assault_objective_use()
+{
+ // activate objective
+ self.health = 100;
+ //print("^2Activated objective ", self.targetname, "=", etos(self), "\n");
+ //print("Activator is ", activator.classname, "\n");
+
+ entity oldself;
+ oldself = self;
+
+ for(self = world; (self = find(self, target, oldself.targetname)); )
+ {
+ if(self.classname == "target_objective_decrease")
+ target_objective_decrease_activate();
+ }
+
+ self = oldself;
+}
+
+vector target_objective_spawn_evalfunc(entity player, entity spot, vector current)
+{
+ if(self.health < 0 || self.health >= ASSAULT_VALUE_INACTIVE)
+ return '-1 0 0';
+ return current;
+}
+
+// reset this objective. Used when spawning an objective
+// and when a new round starts
+void assault_objective_reset()
+{
+ self.health = ASSAULT_VALUE_INACTIVE;
+}
+
+// decrease the health of targeted objectives
+void assault_objective_decrease_use()
+{
+ if(activator.team != assault_attacker_team)
+ {
+ // wrong team triggered decrease
+ return;
+ }
+
+ if(other.assault_sprite)
+ {
+ WaypointSprite_Disown(other.assault_sprite, waypointsprite_deadlifetime);
+ if(other.classname == "func_assault_destructible")
+ other.sprite = world;
+ }
+ else
+ return; // already activated! cannot activate again!
+
+ if(self.enemy.health < ASSAULT_VALUE_INACTIVE)
+ {
+ if(self.enemy.health - self.dmg > 0.5)
+ {
+ PlayerTeamScore_Add(activator, SP_SCORE, ST_SCORE, self.dmg);
+ self.enemy.health = self.enemy.health - self.dmg;
+ }
+ else
+ {
+ PlayerTeamScore_Add(activator, SP_SCORE, ST_SCORE, self.enemy.health);
+ PlayerTeamScore_Add(activator, SP_ASSAULT_OBJECTIVES, ST_ASSAULT_OBJECTIVES, 1);
+ self.enemy.health = -1;
+
+ entity oldself, oldactivator;
+
+ oldself = self;
+ self = oldself.enemy;
+ if(self.message)
+ {
+ entity player;
+ string s;
+ FOR_EACH_PLAYER(player)
+ {
+ s = strcat(self.message, "\n");
+ centerprint(player, s);
+ }
+ }
+
+ oldactivator = activator;
+ activator = oldself;
+ SUB_UseTargets();
+ activator = oldactivator;
+ self = oldself;
+ }
+ }
+}
+
+void assault_setenemytoobjective()
+{
+ entity objective;
+ for(objective = world; (objective = find(objective, targetname, self.target)); )
+ {
+ if(objective.classname == "target_objective")
+ {
+ if(self.enemy == world)
+ self.enemy = objective;
+ else
+ objerror("more than one objective as target - fix the map!");
+ break;
+ }
+ }
+
+ if(self.enemy == world)
+ objerror("no objective as target - fix the map!");
+}
+
+float assault_decreaser_sprite_visible(entity e)
+{
+ entity decreaser;
+
+ decreaser = self.assault_decreaser;
+
+ if(decreaser.enemy.health >= ASSAULT_VALUE_INACTIVE)
+ return FALSE;
+
+ return TRUE;
+}
+
+void target_objective_decrease_activate()
+{
+ entity ent, spr;
+ self.owner = world;
+ for(ent = world; (ent = find(ent, target, self.targetname)); )
+ {
+ if(ent.assault_sprite != world)
+ {
+ WaypointSprite_Disown(ent.assault_sprite, waypointsprite_deadlifetime);
+ if(ent.classname == "func_assault_destructible")
+ ent.sprite = world;
+ }
+
+ spr = WaypointSprite_SpawnFixed("<placeholder>", 0.5 * (ent.absmin + ent.absmax), ent, assault_sprite, RADARICON_OBJECTIVE, '1 0.5 0');
+ spr.assault_decreaser = self;
+ spr.waypointsprite_visible_for_player = assault_decreaser_sprite_visible;
+ spr.classname = "sprite_waypoint";
+ WaypointSprite_UpdateRule(spr, assault_attacker_team, SPRITERULE_TEAMPLAY);
+ if(ent.classname == "func_assault_destructible")
+ {
+ WaypointSprite_UpdateSprites(spr, "as-defend", "as-destroy", "as-destroy");
+ WaypointSprite_UpdateMaxHealth(spr, ent.max_health);
+ WaypointSprite_UpdateHealth(spr, ent.health);
+ ent.sprite = spr;
+ }
+ else
+ WaypointSprite_UpdateSprites(spr, "as-defend", "as-push", "as-push");
+ }
+}
+
+void target_objective_decrease_findtarget()
+{
+ assault_setenemytoobjective();
+}
+
+void target_assault_roundend_reset()
+{
+ //print("round end reset\n");
+ self.cnt = self.cnt + 1; // up round counter
+ self.winning = 0; // up round
+}
+
+void target_assault_roundend_use()
+{
+ self.winning = 1; // round has been won by attackers
+}
+
+void assault_roundstart_use()
+{
+ activator = self;
+ SUB_UseTargets();
+
+#ifdef TTURRETS_ENABLED
+ entity ent, oldself;
+
+ //(Re)spawn all turrets
+ oldself = self;
+ ent = find(world, classname, "turret_main");
+ while(ent) {
+ // Swap turret teams
+ if(ent.team == NUM_TEAM_1)
+ ent.team = NUM_TEAM_2;
+ else
+ ent.team = NUM_TEAM_1;
+
+ self = ent;
+
+ // Dubbles as teamchange
+ turret_stdproc_respawn();
+
+ ent = find(ent, classname, "turret_main");
+ }
+ self = oldself;
+#endif
+}
+
+void assault_wall_think()
+{
+ if(self.enemy.health < 0)
+ {
+ self.model = "";
+ self.solid = SOLID_NOT;
+ }
+ else
+ {
+ self.model = self.mdl;
+ self.solid = SOLID_BSP;
+ }
+
+ self.nextthink = time + 0.2;
+}
+
+// trigger new round
+// reset objectives, toggle spawnpoints, reset triggers, ...
+void vehicles_clearrturn();
+void vehicles_spawn();
+void assault_new_round()
+{
+ entity oldself;
+ //bprint("ASSAULT: new round\n");
+
+ oldself = self;
+ // Eject players from vehicles
+ FOR_EACH_PLAYER(self)
+ {
+ if(self.vehicle)
+ vehicles_exit(VHEF_RELESE);
+ }
+
+ self = findchainflags(vehicle_flags, VHF_ISVEHICLE);
+ while(self)
+ {
+ vehicles_clearrturn();
+ vehicles_spawn();
+ self = self.chain;
+ }
+
+ self = oldself;
+
+ // up round counter
+ self.winning = self.winning + 1;
+
+ // swap attacker/defender roles
+ if(assault_attacker_team == NUM_TEAM_1)
+ assault_attacker_team = NUM_TEAM_2;
+ else
+ assault_attacker_team = NUM_TEAM_1;
+
+ entity ent;
+ for(ent = world; (ent = nextent(ent)); )
+ {
+ if(clienttype(ent) == CLIENTTYPE_NOTACLIENT)
+ {
+ if(ent.team_saved == NUM_TEAM_1)
+ ent.team_saved = NUM_TEAM_2;
+ else if(ent.team_saved == NUM_TEAM_2)
+ ent.team_saved = NUM_TEAM_1;
+ }
+ }
+
+ // reset the level with a countdown
+ cvar_set("timelimit", ftos(ceil(time - game_starttime) / 60));
+ ReadyRestart_force(); // sets game_starttime
+}
+
+// spawnfuncs
+void spawnfunc_info_player_attacker()
+{
+ if not(g_assault) { remove(self); return; }
+
+ self.team = NUM_TEAM_1; // red, gets swapped every round
+ spawnfunc_info_player_deathmatch();
+}
+
+void spawnfunc_info_player_defender()
+{
+ if not(g_assault) { remove(self); return; }
+
+ self.team = NUM_TEAM_2; // blue, gets swapped every round
+ spawnfunc_info_player_deathmatch();
+}
+
+void spawnfunc_target_objective()
+{
+ if not(g_assault) { remove(self); return; }
+
+ self.classname = "target_objective";
+ self.use = assault_objective_use;
+ assault_objective_reset();
+ self.reset = assault_objective_reset;
+ self.spawn_evalfunc = target_objective_spawn_evalfunc;
+}
+
+void spawnfunc_target_objective_decrease()
+{
+ if not(g_assault) { remove(self); return; }
+
+ self.classname = "target_objective_decrease";
+
+ if(!self.dmg)
+ self.dmg = 101;
+
+ self.use = assault_objective_decrease_use;
+ self.health = ASSAULT_VALUE_INACTIVE;
+ self.max_health = ASSAULT_VALUE_INACTIVE;
+ self.enemy = world;
+
+ InitializeEntity(self, target_objective_decrease_findtarget, INITPRIO_FINDTARGET);
+}
+
+// destructible walls that can be used to trigger target_objective_decrease
+void spawnfunc_func_assault_destructible()
+{
+ if not(g_assault) { remove(self); return; }
+
+ self.spawnflags = 3;
+ self.classname = "func_assault_destructible";
+
+ if(assault_attacker_team == NUM_TEAM_1)
+ self.team = NUM_TEAM_2;
+ else
+ self.team = NUM_TEAM_1;
+
+ spawnfunc_func_breakable();
+}
+
+void spawnfunc_func_assault_wall()
+{
+ if not(g_assault) { remove(self); return; }
+
+ self.classname = "func_assault_wall";
+ self.mdl = self.model;
+ setmodel(self, self.mdl);
+ self.solid = SOLID_BSP;
+ self.think = assault_wall_think;
+ self.nextthink = time;
+ InitializeEntity(self, assault_setenemytoobjective, INITPRIO_FINDTARGET);
+}
+
+void spawnfunc_target_assault_roundend()
+{
+ if not(g_assault) { remove(self); return; }
+
+ self.winning = 0; // round not yet won by attackers
+ self.classname = "target_assault_roundend";
+ self.use = target_assault_roundend_use;
+ self.cnt = 0; // first round
+ self.reset = target_assault_roundend_reset;
+}
+
+void spawnfunc_target_assault_roundstart()
+{
+ if not(g_assault) { remove(self); return; }
+
+ assault_attacker_team = NUM_TEAM_1;
+ self.classname = "target_assault_roundstart";
+ self.use = assault_roundstart_use;
+ self.reset2 = assault_roundstart_use;
+ InitializeEntity(self, assault_roundstart_use, INITPRIO_FINDTARGET);
+}
+
+// legacy bot code
+void havocbot_goalrating_ast_targets(float ratingscale)
+{
+ entity ad, best, wp, tod;
+ float radius, found, bestvalue;
+ vector p;
+
+ ad = findchain(classname, "func_assault_destructible");
+
+ for (; ad; ad = ad.chain)
+ {
+ if (ad.target == "")
+ continue;
+
+ if not(ad.bot_attack)
+ continue;
+
+ found = FALSE;
+ for(tod = world; (tod = find(tod, targetname, ad.target)); )
+ {
+ if(tod.classname == "target_objective_decrease")
+ {
+ if(tod.enemy.health > 0 && tod.enemy.health < ASSAULT_VALUE_INACTIVE)
+ {
+ // dprint(etos(ad),"\n");
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ if(!found)
+ {
+ /// dprint("target not found\n");
+ continue;
+ }
+ /// dprint("target #", etos(ad), " found\n");
+
+
+ p = 0.5 * (ad.absmin + ad.absmax);
+ // dprint(vtos(ad.origin), " ", vtos(ad.absmin), " ", vtos(ad.absmax),"\n");
+ // te_knightspike(p);
+ // te_lightning2(world, '0 0 0', p);
+
+ // Find and rate waypoints around it
+ found = FALSE;
+ best = world;
+ bestvalue = 99999999999;
+ for(radius=0; radius<1500 && !found; radius+=500)
+ {
+ for(wp=findradius(p, radius); wp; wp=wp.chain)
+ {
+ if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
+ if(wp.classname=="waypoint")
+ if(checkpvs(wp.origin, ad))
+ {
+ found = TRUE;
+ if(wp.cnt<bestvalue)
+ {
+ best = wp;
+ bestvalue = wp.cnt;
+ }
+ }
+ }
+ }
+
+ if(best)
+ {
+ /// dprint("waypoints around target were found\n");
+ // te_lightning2(world, '0 0 0', best.origin);
+ // te_knightspike(best.origin);
+
+ navigation_routerating(best, ratingscale, 4000);
+ best.cnt += 1;
+
+ self.havocbot_attack_time = 0;
+
+ if(checkpvs(self.view_ofs,ad))
+ if(checkpvs(self.view_ofs,best))
+ {
+ // dprint("increasing attack time for this target\n");
+ self.havocbot_attack_time = time + 2;
+ }
+ }
+ }
+}
+
+void havocbot_role_ast_offense()
+{
+ if(self.deadflag != DEAD_NO)
+ {
+ self.havocbot_attack_time = 0;
+ havocbot_ast_reset_role(self);
+ return;
+ }
+
+ // Set the role timeout if necessary
+ if (!self.havocbot_role_timeout)
+ self.havocbot_role_timeout = time + 120;
+
+ if (time > self.havocbot_role_timeout)
+ {
+ havocbot_ast_reset_role(self);
+ return;
+ }
+
+ if(self.havocbot_attack_time>time)
+ return;
+
+ if (self.bot_strategytime < time)
+ {
+ navigation_goalrating_start();
+ havocbot_goalrating_enemyplayers(20000, self.origin, 650);
+ havocbot_goalrating_ast_targets(20000);
+ havocbot_goalrating_items(15000, self.origin, 10000);
+ navigation_goalrating_end();
+
+ self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ }
+}
+
+void havocbot_role_ast_defense()
+{
+ if(self.deadflag != DEAD_NO)
+ {
+ self.havocbot_attack_time = 0;
+ havocbot_ast_reset_role(self);
+ return;
+ }
+
+ // Set the role timeout if necessary
+ if (!self.havocbot_role_timeout)
+ self.havocbot_role_timeout = time + 120;
+
+ if (time > self.havocbot_role_timeout)
+ {
+ havocbot_ast_reset_role(self);
+ return;
+ }
+
+ if(self.havocbot_attack_time>time)
+ return;
+
+ if (self.bot_strategytime < time)
+ {
+ navigation_goalrating_start();
+ havocbot_goalrating_enemyplayers(20000, self.origin, 3000);
+ havocbot_goalrating_ast_targets(20000);
+ havocbot_goalrating_items(15000, self.origin, 10000);
+ navigation_goalrating_end();
+
+ self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ }
+}
+
+void havocbot_role_ast_setrole(entity bot, float role)
+{
+ switch(role)
+ {
+ case HAVOCBOT_AST_ROLE_DEFENSE:
+ bot.havocbot_role = havocbot_role_ast_defense;
+ bot.havocbot_role_flags = HAVOCBOT_AST_ROLE_DEFENSE;
+ bot.havocbot_role_timeout = 0;
+ break;
+ case HAVOCBOT_AST_ROLE_OFFENSE:
+ bot.havocbot_role = havocbot_role_ast_offense;
+ bot.havocbot_role_flags = HAVOCBOT_AST_ROLE_OFFENSE;
+ bot.havocbot_role_timeout = 0;
+ break;
+ }
+}
+
+void havocbot_ast_reset_role(entity bot)
+{
+ if(self.deadflag != DEAD_NO)
+ return;
+
+ if(bot.team == assault_attacker_team)
+ havocbot_role_ast_setrole(bot, HAVOCBOT_AST_ROLE_OFFENSE);
+ else
+ havocbot_role_ast_setrole(bot, HAVOCBOT_AST_ROLE_DEFENSE);
+}
+
+// mutator hooks
+MUTATOR_HOOKFUNCTION(assault_PlayerSpawn)
+{
+ if(self.team == assault_attacker_team)
+ centerprint(self, "You are attacking!");
+ else
+ centerprint(self, "You are defending!");
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(assault_TurretSpawn)
+{
+ if not (self.team)
+ self.team = 14;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(assault_VehicleSpawn)
+{
+ self.nextthink = time + 0.5;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(assault_BotRoles)
+{
+ havocbot_ast_reset_role(self);
+ return TRUE;
+}
+
+// scoreboard setup
+void assault_ScoreRules()
+{
+ ScoreRules_basics(2, SFL_SORT_PRIO_SECONDARY, SFL_SORT_PRIO_SECONDARY, TRUE);
+ ScoreInfo_SetLabel_TeamScore( ST_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY);
+ ScoreRules_basics_end();
+}
+
+MUTATOR_DEFINITION(gamemode_assault)
+{
+ MUTATOR_HOOK(PlayerSpawn, assault_PlayerSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(TurretSpawn, assault_TurretSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(VehicleSpawn, assault_VehicleSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(HavocBot_ChooseRule, assault_BotRoles, CBC_ORDER_ANY);
+
+ MUTATOR_ONADD
+ {
+ if(time > 1) // game loads at time 1
+ error("This is a game type and it cannot be added at runtime.");
+ assault_ScoreRules();
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ // we actually cannot roll back assault_Initialize here
+ // BUT: we don't need to! If this gets called, adding always
+ // succeeds.
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ print("This is a game type and it cannot be removed at runtime.");
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+// sprites
+.entity assault_decreaser;
+.entity assault_sprite;
+
+// legacy bot defs
+#define HAVOCBOT_AST_ROLE_NONE 0
+#define HAVOCBOT_AST_ROLE_DEFENSE 2
+#define HAVOCBOT_AST_ROLE_OFFENSE 4
+
+.float havocbot_role_flags;
+.float havocbot_attack_time;
+
+.void() havocbot_role;
+.void() havocbot_previous_role;
+
+void() havocbot_role_ast_defense;
+void() havocbot_role_ast_offense;
+.entity havocbot_ast_target;
+
+void(entity bot) havocbot_ast_reset_role;
+
+void(float ratingscale, vector org, float sradius) havocbot_goalrating_items;
+void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
+
+// scoreboard stuff
+#define ST_ASSAULT_OBJECTIVES 1
+#define SP_ASSAULT_OBJECTIVES 4
+
+// predefined spawnfuncs
+void spawnfunc_func_breakable();
+void target_objective_decrease_activate();
\ No newline at end of file
--- /dev/null
+float total_players;
+float redalive, bluealive, yellowalive, pinkalive;
+.float redalive_stat, bluealive_stat, yellowalive_stat, pinkalive_stat;
+float ca_teams;
+float allowed_to_spawn;
+
+void CA_count_alive_players()
+{
+ entity e;
+ total_players = redalive = bluealive = yellowalive = pinkalive = 0;
+ FOR_EACH_PLAYER(e) {
+ if(e.team == NUM_TEAM_1)
+ {
+ ++total_players;
+ if (e.health >= 1) ++redalive;
+ }
+ else if(e.team == NUM_TEAM_2)
+ {
+ ++total_players;
+ if (e.health >= 1) ++bluealive;
+ }
+ else if(e.team == NUM_TEAM_3)
+ {
+ ++total_players;
+ if (e.health >= 1) ++yellowalive;
+ }
+ else if(e.team == NUM_TEAM_4)
+ {
+ ++total_players;
+ if (e.health >= 1) ++pinkalive;
+ }
+ }
+ FOR_EACH_REALCLIENT(e) {
+ e.redalive_stat = redalive;
+ e.bluealive_stat = bluealive;
+ e.yellowalive_stat = yellowalive;
+ e.pinkalive_stat = pinkalive;
+ }
+}
+
+float CA_GetWinnerTeam()
+{
+ float winner_team = 0;
+ if(redalive >= 1)
+ winner_team = NUM_TEAM_1;
+ if(bluealive >= 1)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_2;
+ }
+ if(yellowalive >= 1)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_3;
+ }
+ if(pinkalive >= 1)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_4;
+ }
+ if(winner_team)
+ return winner_team;
+ return -1; // no player left
+}
+
+#define CA_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
+#define CA_ALIVE_TEAMS_OK() (CA_ALIVE_TEAMS() == ca_teams)
+float CA_CheckWinner()
+{
+ if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_OVER);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_OVER);
+ allowed_to_spawn = FALSE;
+ round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
+ return 1;
+ }
+
+ CA_count_alive_players();
+ if(CA_ALIVE_TEAMS() > 1)
+ return 0;
+
+ float winner_team = CA_GetWinnerTeam();
+ if(winner_team > 0)
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, APP_TEAM_NUM_4(winner_team, CENTER_ROUND_TEAM_WIN_));
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(winner_team, INFO_ROUND_TEAM_WIN_));
+ TeamScore_AddToTeam(winner_team, ST_SCORE, +1);
+ }
+ else if(winner_team == -1)
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_TIED);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_TIED);
+ }
+
+ allowed_to_spawn = FALSE;
+ round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
+ return 1;
+}
+
+void CA_RoundStart()
+{
+ if(inWarmupStage)
+ allowed_to_spawn = TRUE;
+ else
+ allowed_to_spawn = FALSE;
+}
+
+float prev_total_players;
+float CA_CheckTeams()
+{
+ allowed_to_spawn = TRUE;
+ CA_count_alive_players();
+ if(CA_ALIVE_TEAMS_OK())
+ {
+ if(prev_total_players > 0)
+ Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_MISSING_TEAMS);
+ prev_total_players = -1;
+ return 1;
+ }
+ if(prev_total_players != total_players)
+ {
+ float p1 = 0, p2 = 0, p3 = 0, p4 = 0;
+ if(!redalive) p1 = NUM_TEAM_1;
+ if(!bluealive) p2 = NUM_TEAM_2;
+ if(ca_teams >= 3)
+ if(!yellowalive) p3 = NUM_TEAM_3;
+ if(ca_teams >= 4)
+ if(!pinkalive) p4 = NUM_TEAM_4;
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_MISSING_TEAMS, p1, p2, p3, p4);
+ prev_total_players = total_players;
+ }
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(ca_PlayerSpawn)
+{
+ self.caplayer = 1;
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_PutClientInServer)
+{
+ if(!allowed_to_spawn)
+ {
+ self.classname = "observer";
+ if(!self.caplayer)
+ {
+ self.caplayer = 0.5;
+ if(clienttype(self) == CLIENTTYPE_REAL)
+ sprint(self, "You will join the game in the next round.\n");
+ }
+ }
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_reset_map_players)
+{
+ FOR_EACH_CLIENT(self)
+ {
+ if(self.caplayer)
+ {
+ self.classname = "player";
+ self.caplayer = 1;
+ PutClientInServer();
+ }
+ }
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_ClientConnect)
+{
+ self.classname = "observer";
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_reset_map_global)
+{
+ allowed_to_spawn = TRUE;
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_GetTeamCount)
+{
+ ca_teams = autocvar_g_ca_teams_override;
+ if(ca_teams < 2)
+ ca_teams = autocvar_g_ca_teams;
+ ca_teams = bound(2, ca_teams, 4);
+ ret_float = ca_teams;
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_PlayerDies)
+{
+ if(!allowed_to_spawn)
+ self.respawn_flags = RESPAWN_SILENT;
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_ForbidPlayerScore_Clear)
+{
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_MakePlayerObserver)
+{
+ if(self.killindicator_teamchange == -2)
+ self.caplayer = 0;
+ if(self.caplayer)
+ self.frags = FRAGS_LMS_LOSER;
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_ForbidThrowCurrentWeapon)
+{
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_GiveFragsForKill)
+{
+ frag_score = 0; // score will be given to the winner team when the round ends
+ return 1;
+}
+
+void ca_Initialize()
+{
+ allowed_to_spawn = TRUE;
+
+ round_handler_Spawn(CA_CheckTeams, CA_CheckWinner, CA_RoundStart);
+ round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
+
+ addstat(STAT_REDALIVE, AS_INT, redalive_stat);
+ addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat);
+ addstat(STAT_YELLOWALIVE, AS_INT, yellowalive_stat);
+ addstat(STAT_PINKALIVE, AS_INT, pinkalive_stat);
+}
+
+MUTATOR_DEFINITION(gamemode_ca)
+{
+ MUTATOR_HOOK(PlayerSpawn, ca_PlayerSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PutClientInServer, ca_PutClientInServer, CBC_ORDER_ANY);
+ MUTATOR_HOOK(MakePlayerObserver, ca_MakePlayerObserver, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ClientConnect, ca_ClientConnect, CBC_ORDER_ANY);
+ MUTATOR_HOOK(reset_map_global, ca_reset_map_global, CBC_ORDER_ANY);
+ MUTATOR_HOOK(reset_map_players, ca_reset_map_players, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GetTeamCount, ca_GetTeamCount, CBC_ORDER_EXCLUSIVE);
+ MUTATOR_HOOK(PlayerDies, ca_PlayerDies, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ForbidPlayerScore_Clear, ca_ForbidPlayerScore_Clear, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ForbidThrowCurrentWeapon, ca_ForbidThrowCurrentWeapon, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GiveFragsForKill, ca_GiveFragsForKill, CBC_ORDER_FIRST);
+
+ MUTATOR_ONADD
+ {
+ if(time > 1) // game loads at time 1
+ error("This is a game type and it cannot be added at runtime.");
+ ca_Initialize();
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ print("This is a game type and it cannot be removed at runtime.");
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+// should be removed in the future, as other code should not have to care
+.float caplayer; // 0.5 if scheduled to join the next round
+
{
entity head;
float old_delay, old_team, real_team;
+ string msg = "dom-neut";
// now that the delay has expired, switch to the latest team to lay claim to this point
head = self.owner;
SUB_UseTargets ();
self.delay = old_delay;
self.team = old_team;
+
+ switch(self.team)
+ {
+ case NUM_TEAM_1: msg = "dom-red"; break;
+ case NUM_TEAM_2: msg = "dom-blue"; break;
+ case NUM_TEAM_3: msg = "dom-yellow"; break;
+ case NUM_TEAM_4: msg = "dom-pink"; break;
+ }
- WaypointSprite_UpdateSprites(self.sprite, strcat("dom-", Team_ColorName_Lower(self.goalentity.team)), "", "");
+ WaypointSprite_UpdateSprites(self.sprite, msg, "", "");
total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
for(head = world; (head = find(head, classname, "dom_controlpoint")) != world; )
-void freezetag_Initialize()
+.float freezetag_frozen_time;
+.float freezetag_frozen_timeout;
+.float freezetag_revive_progress;
+.entity freezetag_ice;
+#define ICE_MAX_ALPHA 1
+#define ICE_MIN_ALPHA 0.1
+float freezetag_teams;
+
+void freezetag_count_alive_players()
{
- precache_model("models/ice/ice.md3");
- warmup = time + autocvar_g_start_delay + autocvar_g_freezetag_warmup;
- ScoreRules_freezetag();
+ entity e;
+ total_players = redalive = bluealive = yellowalive = pinkalive = 0;
+ FOR_EACH_PLAYER(e) {
+ if(e.team == NUM_TEAM_1 && e.health >= 1)
+ {
+ ++total_players;
+ if (!e.freezetag_frozen) ++redalive;
+ }
+ else if(e.team == NUM_TEAM_2 && e.health >= 1)
+ {
+ ++total_players;
+ if (!e.freezetag_frozen) ++bluealive;
+ }
+ else if(e.team == NUM_TEAM_3 && e.health >= 1)
+ {
+ ++total_players;
+ if (!e.freezetag_frozen) ++yellowalive;
+ }
+ else if(e.team == NUM_TEAM_4 && e.health >= 1)
+ {
+ ++total_players;
+ if (!e.freezetag_frozen) ++pinkalive;
+ }
+ }
+ FOR_EACH_REALCLIENT(e) {
+ e.redalive_stat = redalive;
+ e.bluealive_stat = bluealive;
+ e.yellowalive_stat = yellowalive;
+ e.pinkalive_stat = pinkalive;
+ }
}
+#define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
+#define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == freezetag_teams)
-void freezetag_CheckWinner()
+float prev_total_players;
+float freezetag_CheckTeams()
{
- if(time <= game_starttime) // game didn't even start yet! nobody can win in that case.
- return;
+ if(FREEZETAG_ALIVE_TEAMS_OK())
+ {
+ if(prev_total_players > 0)
+ Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_MISSING_TEAMS);
+ prev_total_players = -1;
+ return 1;
+ }
+ if(prev_total_players != total_players)
+ {
+ float p1 = 0, p2 = 0, p3 = 0, p4 = 0;
+ if(!redalive) p1 = NUM_TEAM_1;
+ if(!bluealive) p2 = NUM_TEAM_2;
+ if(freezetag_teams >= 3)
+ if(!yellowalive) p3 = NUM_TEAM_3;
+ if(freezetag_teams >= 4)
+ if(!pinkalive) p4 = NUM_TEAM_4;
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_MISSING_TEAMS, p1, p2, p3, p4);
+ prev_total_players = total_players;
+ }
+ return 0;
+}
- if(next_round || (time > warmup - autocvar_g_freezetag_warmup && time < warmup))
- return; // already waiting for next round to start
+float freezetag_getWinnerTeam()
+{
+ float winner_team = 0;
+ if(redalive >= 1)
+ winner_team = NUM_TEAM_1;
+ if(bluealive >= 1)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_2;
+ }
+ if(yellowalive >= 1)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_3;
+ }
+ if(pinkalive >= 1)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_4;
+ }
+ if(winner_team)
+ return winner_team;
+ return -1; // no player left
+}
- if((redalive >= 1 && bluealive >= 1)
- || (redalive >= 1 && yellowalive >= 1)
- || (redalive >= 1 && pinkalive >= 1)
- || (bluealive >= 1 && yellowalive >= 1)
- || (bluealive >= 1 && pinkalive >= 1)
- || (yellowalive >= 1 && pinkalive >= 1))
- return; // we still have active players on two or more teams, nobody won yet
+float freezetag_CheckWinner()
+{
+ entity e;
+ if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
+ {
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_OVER);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_OVER);
+ FOR_EACH_PLAYER(e)
+ e.freezetag_frozen_timeout = 0;
+ round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
+ return 1;
+ }
- entity e, winner;
- winner = world;
+ if(FREEZETAG_ALIVE_TEAMS() > 1)
+ return 0;
- FOR_EACH_PLAYER(e)
+ float winner_team;
+ winner_team = freezetag_getWinnerTeam();
+ if(winner_team > 0)
{
- if(e.freezetag_frozen == 0 && e.health >= 1) // here's one player from the winning team... good
- {
- winner = e;
- break; // break, we found the winner
- }
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, APP_TEAM_NUM_4(winner_team, CENTER_ROUND_TEAM_WIN_));
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(winner_team, INFO_ROUND_TEAM_WIN_));
+ TeamScore_AddToTeam(winner_team, ST_SCORE, +1);
}
-
- if(winner != world) // just in case a winner wasn't found
+ else if(winner_team == -1)
{
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, APP_TEAM_NUM_4(winner.team, CENTER_FREEZETAG_ROUND_WIN_));
- Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(winner.team, INFO_FREEZETAG_ROUND_WIN_));
- TeamScore_AddToTeam(winner.team, ST_SCORE, +1);
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_TIED);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_TIED);
}
- next_round = time + 5;
+ FOR_EACH_PLAYER(e)
+ e.freezetag_frozen_timeout = 0;
+ round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
+ return 1;
}
// this is needed to allow the player to turn his view around (fixangle can't
self.nextthink = time;
}
+void freezetag_Add_Score(entity attacker)
+{
+ if(attacker == self)
+ {
+ // you froze your own dumb self
+ // counted as "suicide" already
+ PlayerScore_Add(self, SP_SCORE, -1);
+ }
+ else if(IS_PLAYER(attacker))
+ {
+ // got frozen by an enemy
+ // counted as "kill" and "death" already
+ PlayerScore_Add(self, SP_SCORE, -1);
+ PlayerScore_Add(attacker, SP_SCORE, +1);
+ }
+ // else nothing - got frozen by the game type rules themselves
+}
+
void freezetag_Freeze(entity attacker)
{
if(self.freezetag_frozen)
return;
self.freezetag_frozen = 1;
+ self.freezetag_frozen_time = time;
self.freezetag_revive_progress = 0;
self.health = 1;
+ if(autocvar_g_freezetag_frozen_maxtime > 0)
+ self.freezetag_frozen_timeout = time + autocvar_g_freezetag_frozen_maxtime;
+
+ freezetag_count_alive_players();
entity ice;
ice = spawn();
ice.think = freezetag_Ice_Think;
ice.nextthink = time;
ice.frame = floor(random() * 21); // ice model has 20 different looking frames
+ ice.alpha = ICE_MAX_ALPHA;
+ ice.colormod = Team_ColorRGB(self.team);
+ ice.glowmod = ice.colormod;
setmodel(ice, "models/ice/ice.md3");
- entity oldself;
- oldself = self;
- self = ice;
- freezetag_Ice_Think();
- self = oldself;
+ self.freezetag_ice = ice;
RemoveGrapplingHook(self);
// add waypoint
WaypointSprite_Spawn("freezetag_frozen", 0, 0, self, '0 0 64', world, self.team, self, waypointsprite_attached, TRUE, RADARICON_WAYPOINT, '0.25 0.90 1');
- if(attacker == self)
- {
- // you froze your own dumb self
- // counted as "suicide" already
- PlayerScore_Add(self, SP_SCORE, -1);
- }
- else if(attacker.classname == "player")
- {
- // got frozen by an enemy
- // counted as "kill" and "death" already
- PlayerScore_Add(self, SP_SCORE, -1);
- PlayerScore_Add(attacker, SP_SCORE, +1);
- }
- else
- {
- // nothing - got frozen by the game type rules themselves
- }
+ freezetag_Add_Score(attacker);
}
void freezetag_Unfreeze(entity attacker)
{
self.freezetag_frozen = 0;
+ self.freezetag_frozen_time = 0;
+ self.freezetag_frozen_timeout = 0;
self.freezetag_revive_progress = 0;
- self.health = autocvar_g_balance_health_start;
- // remove the ice block
- entity ice;
- for(ice = world; (ice = find(ice, classname, "freezetag_ice")); ) if(ice.owner == self)
- {
- remove(ice);
- break;
- }
+ remove(self.freezetag_ice);
+ self.freezetag_ice = world;
- // remove waypoint
if(self.waypointsprite_attached)
WaypointSprite_Kill(self.waypointsprite_attached);
}
MUTATOR_HOOKFUNCTION(freezetag_RemovePlayer)
{
- if(self.freezetag_frozen == 0 && self.health >= 1)
- {
- if(self.team == NUM_TEAM_1)
- --redalive;
- else if(self.team == NUM_TEAM_2)
- --bluealive;
- else if(self.team == NUM_TEAM_3)
- --yellowalive;
- else if(self.team == NUM_TEAM_4)
- --pinkalive;
- --totalalive;
- }
-
- if(total_players > 2) // only check for winners if we had more than two players (one of them left, don't let the other player win just because of that)
- freezetag_CheckWinner();
-
+ self.health = 0; // neccessary to update correctly alive stats
freezetag_Unfreeze(world);
-
+ freezetag_count_alive_players();
return 1;
}
MUTATOR_HOOKFUNCTION(freezetag_PlayerDies)
{
- if(self.freezetag_frozen == 0)
+ if(round_handler_IsActive())
+ if(round_handler_CountdownRunning())
{
- if(self.team == NUM_TEAM_1)
- --redalive;
- else if(self.team == NUM_TEAM_2)
- --bluealive;
- else if(self.team == NUM_TEAM_3)
- --yellowalive;
- else if(self.team == NUM_TEAM_4)
- --pinkalive;
- --totalalive;
+ if(self.freezetag_frozen)
+ freezetag_Unfreeze(world);
+ freezetag_count_alive_players();
+ return 1; // let the player die so that he can respawn whenever he wants
+ }
- freezetag_Freeze(frag_attacker);
+ // 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)
+ || frag_deathtype == DEATH_TEAMCHANGE || frag_deathtype == DEATH_AUTOTEAMCHANGE)
+ {
+ // let the player die, he will be automatically frozen when he respawns
+ if(!self.freezetag_frozen)
+ {
+ freezetag_Add_Score(frag_attacker);
+ freezetag_count_alive_players();
+ }
+ else
+ freezetag_Unfreeze(world); // remove ice
+ self.freezetag_frozen_timeout = -2; // freeze on respawn
+ return 1;
}
+ if(self.freezetag_frozen)
+ return 1;
+
+ freezetag_Freeze(frag_attacker);
+
if(frag_attacker == frag_target || frag_attacker == world)
{
if(frag_target.classname == STR_PLAYER)
frag_target.health = 1; // "respawn" the player :P
- freezetag_CheckWinner();
-
return 1;
}
MUTATOR_HOOKFUNCTION(freezetag_PlayerSpawn)
{
- freezetag_Unfreeze(world); // start by making sure that all ice blocks are removed
+ if(self.freezetag_frozen_timeout == -1) // if PlayerSpawn is called by reset_map_players
+ return 1; // do nothing, round is starting right now
- if(total_players == 1 && time > game_starttime) // only one player active on server, start a new match immediately
- if(!next_round && warmup && (time < warmup - autocvar_g_freezetag_warmup || time > warmup)) // not awaiting next round
+ if(self.freezetag_frozen_timeout == -2) // player was dead
{
- next_round = time;
+ freezetag_Freeze(world);
return 1;
}
- if(warmup && time > warmup) // spawn too late, freeze player
+
+ freezetag_count_alive_players();
+
+ if(round_handler_IsActive())
+ if(round_handler_IsRoundStarted())
{
Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_SPAWN_LATE);
freezetag_Freeze(world);
return 1;
}
+MUTATOR_HOOKFUNCTION(freezetag_reset_map_players)
+{
+ FOR_EACH_PLAYER(self)
+ {
+ if (self.freezetag_frozen)
+ freezetag_Unfreeze(world);
+ self.freezetag_frozen_timeout = -1;
+ PutClientInServer();
+ self.freezetag_frozen_timeout = 0;
+ }
+ freezetag_count_alive_players();
+ return 1;
+}
+
MUTATOR_HOOKFUNCTION(freezetag_GiveFragsForKill)
{
frag_score = 0; // no frags counted in Freeze Tag
return 1;
}
+.float reviving; // temp var
MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink)
{
float n;
- vector revive_extra_size;
- revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
+ if(gameover)
+ return 1;
+
+ if(self.freezetag_frozen)
+ {
+ // keep health = 1
+ self.pauseregen_finished = time + autocvar_g_balance_pause_health_regen;
+ }
+
+ if(round_handler_IsActive())
+ if(!round_handler_IsRoundStarted())
+ return 1;
entity o;
o = world;
- n = 0;
- FOR_EACH_PLAYER(other) if(self != other)
+ if(self.freezetag_frozen_timeout > 0 && time < self.freezetag_frozen_timeout)
+ self.freezetag_ice.alpha = ICE_MIN_ALPHA + (ICE_MAX_ALPHA - ICE_MIN_ALPHA) * (self.freezetag_frozen_timeout - time) / (self.freezetag_frozen_timeout - self.freezetag_frozen_time);
+
+ if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout)
+ n = -1;
+ else
{
- if(other.freezetag_frozen == 0)
+ vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
+ n = 0;
+ FOR_EACH_PLAYER(other) if(self != other)
{
- if(other.team == self.team)
+ if(other.freezetag_frozen == 0)
{
- if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
+ if(other.team == self.team)
{
- if(!o)
- o = other;
- ++n;
+ if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
+ {
+ if(!o)
+ o = other;
+ if(self.freezetag_frozen)
+ other.reviving = TRUE;
+ ++n;
+ }
}
}
}
if(n && self.freezetag_frozen) // OK, there is at least one teammate reviving us
{
- self.freezetag_revive_progress = bound(0, self.freezetag_revive_progress + frametime * autocvar_g_freezetag_revive_speed, 1);
+ self.freezetag_revive_progress = bound(0, self.freezetag_revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
self.health = max(1, self.freezetag_revive_progress * autocvar_g_balance_health_start);
if(self.freezetag_revive_progress >= 1)
{
freezetag_Unfreeze(self);
+ freezetag_count_alive_players();
+
+ if(n == -1)
+ {
+ Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_AUTO_REVIVED, autocvar_g_freezetag_frozen_maxtime);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_AUTO_REVIVED, self.netname, autocvar_g_freezetag_frozen_maxtime);
+ return 1;
+ }
// EVERY team mate nearby gets a point (even if multiple!)
- FOR_EACH_PLAYER(other) if(self != other)
+ FOR_EACH_PLAYER(other)
{
- if(other.freezetag_frozen == 0)
+ if(other.reviving)
{
- if(other.team == self.team)
- {
- if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
- {
- PlayerScore_Add(other, SP_FREEZETAG_REVIVALS, +1);
- PlayerScore_Add(other, SP_SCORE, +1);
- }
- }
+ PlayerScore_Add(other, SP_FREEZETAG_REVIVALS, +1);
+ PlayerScore_Add(other, SP_SCORE, +1);
}
}
Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname);
Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, self.netname);
- Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVE, self.netname, o.netname);
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVED, self.netname, o.netname);
}
- // now find EVERY teammate within reviving radius, set their revive_progress values correct
- FOR_EACH_PLAYER(other) if(self != other)
+ FOR_EACH_PLAYER(other)
{
- if(other.freezetag_frozen == 0)
+ if(other.reviving)
{
- if(other.team == self.team)
- {
- if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
- other.freezetag_revive_progress = self.freezetag_revive_progress;
- }
+ other.freezetag_revive_progress = self.freezetag_revive_progress;
+ other.reviving = FALSE;
}
}
}
MUTATOR_HOOKFUNCTION(freezetag_PlayerDamage_Calculate)
{
- if(g_freezetag)
- {
- if(frag_target.freezetag_frozen == 1 && frag_deathtype != DEATH_HURTTRIGGER)
- {
- frag_damage = 0;
- frag_force = frag_force * autocvar_g_freezetag_frozen_force;
- }
- }
- return 1;
+ if(frag_target.freezetag_frozen && frag_deathtype != DEATH_HURTTRIGGER)
+ {
+ frag_damage = 0;
+ frag_force = frag_force * autocvar_g_freezetag_frozen_force;
+ }
+ return 1;
}
MUTATOR_HOOKFUNCTION(freezetag_ForbidThrowCurrentWeapon)
return 0;
}
+MUTATOR_HOOKFUNCTION(freezetag_ItemTouch)
+{
+ if (other.freezetag_frozen)
+ return 1;
+ return 0;
+}
+
MUTATOR_HOOKFUNCTION(freezetag_BotRoles)
{
if not(self.deadflag)
else
self.havocbot_role = havocbot_role_ft_offense;
}
-
+
return TRUE;
}
+MUTATOR_HOOKFUNCTION(freezetag_SpectateCopy)
+{
+ self.freezetag_frozen = other.freezetag_frozen;
+ self.freezetag_revive_progress = other.freezetag_revive_progress;
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(freezetag_GetTeamCount)
+{
+ freezetag_teams = autocvar_g_freezetag_teams_override;
+ if(freezetag_teams < 2)
+ freezetag_teams = autocvar_g_freezetag_teams;
+ freezetag_teams = bound(2, freezetag_teams, 4);
+ ret_float = freezetag_teams;
+ return 0;
+}
+
+void freezetag_Initialize()
+{
+ precache_model("models/ice/ice.md3");
+ ScoreRules_freezetag();
+
+ round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null);
+ round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
+
+ addstat(STAT_REDALIVE, AS_INT, redalive_stat);
+ addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat);
+ addstat(STAT_YELLOWALIVE, AS_INT, yellowalive_stat);
+ addstat(STAT_PINKALIVE, AS_INT, pinkalive_stat);
+
+ addstat(STAT_FROZEN, AS_INT, freezetag_frozen);
+ addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress);
+}
+
MUTATOR_DEFINITION(gamemode_freezetag)
{
MUTATOR_HOOK(MakePlayerObserver, freezetag_RemovePlayer, CBC_ORDER_ANY);
MUTATOR_HOOK(ClientDisconnect, freezetag_RemovePlayer, CBC_ORDER_ANY);
MUTATOR_HOOK(PlayerDies, freezetag_PlayerDies, CBC_ORDER_ANY);
MUTATOR_HOOK(PlayerSpawn, freezetag_PlayerSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(reset_map_players, freezetag_reset_map_players, CBC_ORDER_ANY);
MUTATOR_HOOK(GiveFragsForKill, freezetag_GiveFragsForKill, CBC_ORDER_FIRST);
MUTATOR_HOOK(PlayerPreThink, freezetag_PlayerPreThink, CBC_ORDER_FIRST);
MUTATOR_HOOK(PlayerPhysics, freezetag_PlayerPhysics, CBC_ORDER_FIRST);
MUTATOR_HOOK(PlayerDamage_Calculate, freezetag_PlayerDamage_Calculate, CBC_ORDER_ANY);
- MUTATOR_HOOK(ForbidThrowCurrentWeapon, freezetag_ForbidThrowCurrentWeapon, CBC_ORDER_FIRST); //first, last or any? dunno.
+ MUTATOR_HOOK(ForbidThrowCurrentWeapon, freezetag_ForbidThrowCurrentWeapon, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ItemTouch, freezetag_ItemTouch, CBC_ORDER_ANY);
MUTATOR_HOOK(HavocBot_ChooseRule, freezetag_BotRoles, CBC_ORDER_ANY);
+ MUTATOR_HOOK(SpectateCopy, freezetag_SpectateCopy, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GetTeamCount, freezetag_GetTeamCount, CBC_ORDER_EXCLUSIVE);
MUTATOR_ONADD
{
kh_Key_Remove(key);
kh_no_radar_circles = FALSE;
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ARENA_ROUNDSTART, autocvar_g_balance_keyhunt_delay_round);
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_KEYHUNT_ROUNDSTART, autocvar_g_balance_keyhunt_delay_round);
kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round, kh_StartRound);
}
float p1 = kh_CheckPlayers(0), p2 = kh_CheckPlayers(1), p3 = kh_CheckPlayers(2), p4 = kh_CheckPlayers(3);
if not(p1 || p2 || p3 || p4)
{
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ARENA_ROUNDSTART, autocvar_g_balance_keyhunt_delay_round);
+ Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_KEYHUNT_ROUNDSTART, autocvar_g_balance_keyhunt_delay_round);
kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round, kh_StartRound);
}
else
.entity kh_next;
float kh_Key_AllOwnedByWhichTeam();
-// used by arena.qc ready-restart:
typedef void(void) kh_Think_t;
void kh_StartRound();
void kh_Controller_SetThink(float t, kh_Think_t func);
--- /dev/null
+// main functions
+float LMS_NewPlayerLives()
+{
+ float fl;
+ fl = autocvar_fraglimit;
+ if(fl == 0)
+ fl = 999;
+
+ // first player has left the game for dying too much? Nobody else can get in.
+ if(lms_lowest_lives < 1)
+ return 0;
+
+ if(!autocvar_g_lms_join_anytime)
+ if(lms_lowest_lives < fl - autocvar_g_lms_last_join)
+ return 0;
+
+ return bound(1, lms_lowest_lives, fl);
+}
+
+// mutator hooks
+MUTATOR_HOOKFUNCTION(lms_PlayerSpawn)
+{
+ if(IS_PLAYER(self))
+ if(restart_mapalreadyrestarted || (time < game_starttime))
+ PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives());
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_RemovePlayer)
+{
+ // Only if the player cannot play at all
+ if(PlayerScore_Add(self, SP_LMS_RANK, 0) == 666)
+ self.frags = FRAGS_SPECTATOR;
+ else
+ self.frags = FRAGS_LMS_LOSER;
+
+ if(self.killcount != -666)
+ if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0 && self.lms_spectate_warning != 2)
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_NOLIVES, self.netname);
+ else
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_FORFEIT, self.netname);
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_ClientConnect)
+{
+ self.classname = "player";
+ campaign_bots_may_start = 1;
+
+ if(PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives()) <= 0)
+ {
+ PlayerScore_Add(self, SP_LMS_RANK, 666);
+ self.frags = FRAGS_SPECTATOR;
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_PlayerThink)
+{
+ if(self.deadflag == DEAD_DYING)
+ self.deadflag = DEAD_RESPAWNING;
+
+ if not(self.deadflag)
+ if(autocvar_g_lms_campcheck_interval)
+ {
+ vector dist;
+
+ // calculate player movement (in 2 dimensions only, so jumping on one spot doesn't count as movement)
+ dist = self.prevorigin - self.origin;
+ dist_z = 0;
+ self.lms_traveled_distance += fabs(vlen(dist));
+
+ if((autocvar_g_campaign && !campaign_bots_may_start) || (time < game_starttime))
+ {
+ self.lms_nextcheck = time + autocvar_g_lms_campcheck_interval*2;
+ self.lms_traveled_distance = 0;
+ }
+
+ if(time > self.lms_nextcheck)
+ {
+ if(self.lms_traveled_distance < autocvar_g_lms_campcheck_distance)
+ {
+ Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_LMS_CAMPCHECK);
+ if(self.vehicle)
+ Damage(self.vehicle, self, self, autocvar_g_lms_campcheck_damage * 2, DEATH_CAMP, self.vehicle.origin, '0 0 0');
+ else
+ Damage(self, self, self, bound(0, autocvar_g_lms_campcheck_damage, self.health + self.armorvalue * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP, self.origin, '0 0 0');
+ }
+ self.lms_nextcheck = time + autocvar_g_lms_campcheck_interval;
+ self.lms_traveled_distance = 0;
+ }
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_PlayerDamage)
+{
+ if(IS_PLAYER(frag_target))
+ if(IS_PLAYER(frag_attacker))
+ if(frag_attacker != frag_target)
+ {
+ frag_target.lms_traveled_distance = autocvar_g_lms_campcheck_distance;
+ frag_attacker.lms_traveled_distance = autocvar_g_lms_campcheck_distance;
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_ForbidThrowing)
+{
+ // forbode!
+ return TRUE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_GiveFragsForKill)
+{
+ // remove a life
+ float tl;
+ tl = PlayerScore_Add(frag_target, SP_LMS_LIVES, -1);
+ if(tl < lms_lowest_lives)
+ lms_lowest_lives = tl;
+ if(tl <= 0)
+ {
+ if(!lms_next_place)
+ lms_next_place = player_count;
+ else
+ lms_next_place = min(lms_next_place, player_count);
+ PlayerScore_Add(frag_target, SP_LMS_RANK, lms_next_place); // won't ever spawn again
+ --lms_next_place;
+ }
+ frag_score = 0;
+
+ return TRUE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_SetStartItems)
+{
+ start_items &~= IT_UNLIMITED_AMMO;
+ start_ammo_shells = cvar("g_lms_start_ammo_shells");
+ start_ammo_nails = cvar("g_lms_start_ammo_nails");
+ start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
+ start_ammo_cells = cvar("g_lms_start_ammo_cells");
+ start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
+ start_health = cvar("g_lms_start_health");
+ start_armorvalue = cvar("g_lms_start_armor");
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_KeepScore)
+{
+ // don't clear player score
+ return TRUE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_FilterItem)
+{
+ if(autocvar_g_lms_extra_lives)
+ if(self.classname == "item_health_mega")
+ {
+ self.max_health = 1;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_ItemTouch)
+{
+ // give extra lives for mega health
+ if(self.items & IT_HEALTH)
+ {
+ Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_EXTRALIVES);
+ PlayerScore_Add(other, SP_LMS_LIVES, autocvar_g_lms_extra_lives);
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_BotSpawn)
+{
+ // temporary hack to give bots lives
+ if(PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives()) <= 0)
+ {
+ PlayerScore_Add(self, SP_LMS_RANK, 666);
+ self.frags = FRAGS_SPECTATOR;
+ }
+
+ return FALSE;
+}
+
+// scoreboard stuff
+void lms_ScoreRules()
+{
+ ScoreRules_basics(0, 0, 0, FALSE);
+ ScoreInfo_SetLabel_PlayerScore(SP_LMS_LIVES, "lives", SFL_SORT_PRIO_SECONDARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_LMS_RANK, "rank", SFL_LOWER_IS_BETTER | SFL_RANK | SFL_SORT_PRIO_PRIMARY | SFL_ALLOW_HIDE);
+ ScoreRules_basics_end();
+}
+
+void lms_Initialize()
+{
+ lms_lowest_lives = 9999;
+ lms_next_place = 0;
+
+ lms_ScoreRules();
+}
+
+MUTATOR_DEFINITION(gamemode_lms)
+{
+ MUTATOR_HOOK(PlayerSpawn, lms_PlayerSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(MakePlayerObserver, lms_RemovePlayer, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ClientConnect, lms_ClientConnect, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerPreThink, lms_PlayerThink, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerDamage_Calculate, lms_PlayerDamage, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ForbidThrowCurrentWeapon, lms_ForbidThrowing, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GiveFragsForKill, lms_GiveFragsForKill, CBC_ORDER_ANY);
+ MUTATOR_HOOK(SetStartItems, lms_SetStartItems, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ForbidPlayerScore_Clear, lms_KeepScore, CBC_ORDER_ANY);
+ MUTATOR_HOOK(FilterItem, lms_FilterItem, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ItemTouch, lms_ItemTouch, CBC_ORDER_ANY);
+ MUTATOR_HOOK(HavocBot_ChooseRule, lms_BotSpawn, CBC_ORDER_ANY);
+
+ MUTATOR_ONADD
+ {
+ if(time > 1) // game loads at time 1
+ error("This is a game type and it cannot be added at runtime.");
+ lms_Initialize();
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ // we actually cannot roll back lms_Initialize here
+ // BUT: we don't need to! If this gets called, adding always
+ // succeeds.
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ print("This is a game type and it cannot be removed at runtime.");
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+// scoreboard stuff
+#define SP_LMS_LIVES 4
+#define SP_LMS_RANK 5
+
+// lives related defs
+float lms_lowest_lives;
+float lms_next_place;
+float LMS_NewPlayerLives();
\ No newline at end of file
MUTATOR_HOOKFUNCTION(nt_FilterItem)
{
if(nt_IsNewToy(self.weapon))
- self.item_pickupsound = "weapons/weaponpickup_new_toys.ogg";
+ self.item_pickupsound = "weapons/weaponpickup_new_toys.wav";
return 0;
}
if(time > 1) // game loads at time 1
error("This cannot be added at runtime\n");
- precache_sound("weapons/weaponpickup_new_toys.ogg");
+ precache_sound("weapons/weaponpickup_new_toys.wav");
// mark the guns as ok to use by e.g. impulse 99
float i;
MUTATOR_HOOKFUNCTION(superspec_ClientConnect)
{
+ if(clienttype(self) != CLIENTTYPE_REAL)
+ return FALSE;
+
string fn = "superspec-local.options";
float fh;
--- /dev/null
+.float touchexplode_time;
+
+void PlayerTouchExplode(entity p1, entity p2)
+{
+ vector org;
+ org = (p1.origin + p2.origin) * 0.5;
+ org_z += (p1.mins_z + p2.mins_z) * 0.5;
+
+ sound(self, CH_TRIGGER, "weapons/grenade_impact.wav", VOL_BASE, ATTN_NORM);
+ pointparticles(particleeffectnum("explosion_small"), org, '0 0 0', 1);
+
+ entity e;
+ e = spawn();
+ setorigin(e, org);
+ RadiusDamage(e, world, autocvar_g_touchexplode_damage, autocvar_g_touchexplode_edgedamage, autocvar_g_touchexplode_radius, world, autocvar_g_touchexplode_force, DEATH_TOUCHEXPLODE, world);
+ remove(e);
+}
+
+MUTATOR_HOOKFUNCTION(touchexplode_PlayerThink)
+{
+ if(time > self.touchexplode_time)
+ if not(gameover)
+ if(IS_PLAYER(self))
+ if(self.deadflag == DEAD_NO)
+ if not(IS_INDEPENDENT_PLAYER(self))
+ FOR_EACH_PLAYER(other) if(self != other)
+ {
+ if(time > other.touchexplode_time)
+ if(other.deadflag == DEAD_NO)
+ if not(IS_INDEPENDENT_PLAYER(other))
+ if(boxesoverlap(self.absmin, self.absmax, other.absmin, other.absmax))
+ {
+ PlayerTouchExplode(self, other);
+ self.touchexplode_time = other.touchexplode_time = time + 0.2;
+ }
+ }
+
+ return FALSE;
+}
+
+MUTATOR_DEFINITION(mutator_touchexplode)
+{
+ MUTATOR_HOOK(PlayerPreThink, touchexplode_PlayerThink, CBC_ORDER_ANY);
+
+ return FALSE;
+}
+MUTATOR_DECLARATION(gamemode_assault);
+MUTATOR_DECLARATION(gamemode_arena);
+MUTATOR_DECLARATION(gamemode_ca);
MUTATOR_DECLARATION(gamemode_keyhunt);
MUTATOR_DECLARATION(gamemode_freezetag);
MUTATOR_DECLARATION(gamemode_keepaway);
MUTATOR_DECLARATION(gamemode_nexball);
MUTATOR_DECLARATION(gamemode_onslaught);
MUTATOR_DECLARATION(gamemode_domination);
+MUTATOR_DECLARATION(gamemode_lms);
MUTATOR_DECLARATION(mutator_dodging);
MUTATOR_DECLARATION(mutator_invincibleprojectiles);
MUTATOR_DECLARATION(mutator_physical_items);
MUTATOR_DECLARATION(mutator_vampire);
MUTATOR_DECLARATION(mutator_superspec);
+MUTATOR_DECLARATION(mutator_touchexplode);
MUTATOR_DECLARATION(sandbox);
intensity -= autocvar_g_sandbox_object_material_velocity_min; // start from minimum velocity, not actual velocity
intensity = bound(0, intensity * autocvar_g_sandbox_object_material_velocity_factor, 1);
- sound(self, CH_TRIGGER, strcat("object/impact_", self.material, "_", ftos(ceil(random() * 5)) , ".ogg"), VOL_BASE * intensity, ATTN_NORM);
+ sound(self, CH_TRIGGER, strcat("object/impact_", self.material, "_", ftos(ceil(random() * 5)) , ".wav"), VOL_BASE * intensity, ATTN_NORM);
pointparticles(particleeffectnum(strcat("impact_", self.material)), self.origin, '0 0 0', ceil(intensity * 10)); // allow a count from 1 to 10
}
{
// since objects are being loaded for the first time, precache material sounds for each
for (i = 1; i <= 5; i++) // 5 sounds in total
- precache_sound(strcat("object/impact_", e.material, "_", ftos(i), ".ogg"));
+ precache_sound(strcat("object/impact_", e.material, "_", ftos(i), ".wav"));
}
}
if(autocvar_g_sandbox_info > 0)
if(argv(3))
{
for (i = 1; i <= 5; i++) // precache material sounds, 5 in total
- precache_sound(strcat("object/impact_", argv(3), "_", ftos(i), ".ogg"));
+ precache_sound(strcat("object/impact_", argv(3), "_", ftos(i), ".wav"));
e.material = strzone(argv(3));
}
else
{
// telefrag within 1 second of portal creation = amazing
if(time < teleporter.teleport_time + 1)
- AnnounceTo(player, "amazing");
+ Send_Notification(NOTIF_ONE, player, MSG_ANNCE, ANNCE_ACHIEVEMENT_AMAZING);
}
if not(teleporter.enemy)
mutators/base.qh
mutators/mutators.qh
+mutators/gamemode_assault.qh
+mutators/gamemode_arena.qh
+mutators/gamemode_ca.qh
mutators/gamemode_ctf.qh
mutators/gamemode_domination.qh
mutators/gamemode_keyhunt.qh // TODO fix this
mutators/gamemode_keepaway.qh
mutators/gamemode_nexball.qh
+mutators/gamemode_lms.qh
mutators/mutator_dodging.qh
//// tZork Turrets ////
playerdemo.qh
+round_handler.qh
+
// singleplayer stuff
item_key.qh
secret.qh
g_tetris.qc
//runematch.qc
-arena.qc
g_violence.qc
g_damage.qc
command/cmd.qc
command/sv_cmd.qc
-assault.qc
+//assault.qc
ipban.qc
cheats.qc
playerstats.qc
+round_handler.qc
+
../common/explosion_equation.qc
mutators/base.qc
+mutators/gamemode_assault.qc
+mutators/gamemode_arena.qc
+mutators/gamemode_ca.qc
mutators/gamemode_ctf.qc
mutators/gamemode_domination.qc
mutators/gamemode_freezetag.qc
mutators/gamemode_keepaway.qc
mutators/gamemode_nexball.qc
mutators/gamemode_onslaught.qc
+mutators/gamemode_lms.qc
mutators/mutator_invincibleproj.qc
mutators/mutator_new_toys.qc
mutators/mutator_nix.qc
mutators/mutator_physical_items.qc
mutators/sandbox.qc
mutators/mutator_superspec.qc
+mutators/mutator_touchexplode.qc
../warpzonelib/anglestransform.qc
../warpzonelib/mathlib.qc
--- /dev/null
+void round_handler_Think()
+{
+ float f;
+
+ if(time < game_starttime)
+ {
+ round_handler_Reset(game_starttime);
+ return;
+ }
+
+ if(gameover)
+ {
+ round_handler_Reset(0);
+ round_handler_Remove();
+ return;
+ }
+
+ if(self.wait)
+ {
+ self.wait = FALSE;
+ self.cnt = self.count + 1; // init countdown
+ round_starttime = time + self.count;
+ reset_map(TRUE);
+ }
+
+ if(self.cnt > 0) // countdown running
+ {
+ if(self.canRoundStart())
+ {
+ if(self.cnt == self.count + 1)
+ round_starttime = time + self.count;
+ f = self.cnt - 1;
+ if(f == 0)
+ {
+ self.cnt = 0;
+ self.round_endtime = (self.round_timelimit) ? time + self.round_timelimit : 0;
+ self.nextthink = time;
+ if(self.roundStart)
+ self.roundStart();
+ return;
+ }
+ self.cnt = self.cnt - 1;
+ }
+ else
+ {
+ round_handler_Reset(0);
+ }
+ self.nextthink = time + 1; // canRoundStart every second
+ }
+ else
+ {
+ if(self.canRoundEnd())
+ {
+ // schedule a new round
+ self.wait = TRUE;
+ self.nextthink = time + self.delay;
+ }
+ else
+ {
+ self.nextthink = time; // canRoundEnd every frame
+ }
+ }
+}
+
+void round_handler_Init(float the_delay, float the_count, float the_round_timelimit)
+{
+ round_handler.delay = (the_delay > 0) ? the_delay : 0;
+ round_handler.count = fabs(floor(the_count));
+ round_handler.cnt = round_handler.count + 1;
+ round_handler.round_timelimit = (the_round_timelimit > 0) ? the_round_timelimit : 0;
+}
+
+// NOTE: this is only needed because if round_handler spawns at time 1
+// gamestarttime isn't initialized yet
+void round_handler_FirstThink()
+{
+ round_starttime = max(time, game_starttime) + round_handler.count;
+ round_handler.think = round_handler_Think;
+ round_handler.nextthink = max(time, game_starttime);
+}
+
+void round_handler_Spawn(float() canRoundStart_func, float() canRoundEnd_func, void() roundStart_func)
+{
+ if(round_handler)
+ {
+ backtrace("Can't spawn round_handler again!");
+ return;
+ }
+ round_handler = spawn();
+ round_handler.classname = "round_handler";
+
+ round_handler.think = round_handler_FirstThink;
+ round_handler.canRoundStart = canRoundStart_func;
+ round_handler.canRoundEnd = canRoundEnd_func;
+ round_handler.roundStart = roundStart_func;
+ round_handler.wait = FALSE;
+ round_handler_Init(5, 5, 180);
+ round_handler.nextthink = time;
+}
+
+void round_handler_Reset(float next_think)
+{
+ round_handler.wait = FALSE;
+ if(round_handler.count)
+ if(round_handler.cnt < round_handler.count + 1)
+ round_handler.cnt = round_handler.count + 1;
+ round_handler.nextthink = next_think;
+ round_starttime = (next_think) ? (next_think + round_handler.count) : -1;
+}
+
+void round_handler_Remove()
+{
+ remove(round_handler);
+ round_handler = world;
+}
+
--- /dev/null
+entity round_handler;
+.float delay; // stores delay from round end to countdown start
+.float count; // stores initial number of the countdown
+.float wait; // it's set to TRUE when round ends, to FALSE when countdown starts
+.float cnt; // its initial value is .count + 1, then decreased while counting down
+ // reaches 0 when the round starts
+.float round_timelimit;
+.float round_endtime;
+.float() canRoundStart;
+.float() canRoundEnd;
+.void() roundStart;
+
+void round_handler_Init(float the_delay, float the_count, float the_round_timelimit);
+void round_handler_Spawn(float() canRoundStart_func, float() canRoundEnd_func, void() roundStart_func);
+void round_handler_Reset(float next_think);
+void round_handler_Remove();
+
+#define round_handler_IsActive() (round_handler != world)
+#define round_handler_AwaitingNextRound() (round_handler.wait)
+#define round_handler_CountdownRunning() (!round_handler.wait && round_handler.cnt)
+#define round_handler_IsRoundStarted() (!round_handler.wait && !round_handler.cnt)
+#define round_handler_GetEndTime() (round_handler.round_endtime)
+
if(teamscores_entities_count)
return 0;
- if(g_lms) return 0;
- if(g_arena || g_ca) return 0;
+ if(MUTATOR_CALLHOOK(ForbidPlayerScore_Clear)) return 0;
+
if(g_cts) return 0; // in CTS, you don't lose score by observing
if(g_race && g_race_qualifying) return 0; // in qualifying, you don't lose score by observing
s = strcat(s, ":human");
else
s = strcat(s, ":bot");
- if(p.classname != "player" && !g_arena && !g_ca && !g_lms)
+ if(p.classname != "player" && !g_arena && p.caplayer != 1 && !g_lms)
s = strcat(s, ":spectator");
}
else
{
- if(p.classname == "player" || g_arena || g_ca || g_lms)
+ if(p.classname == "player" || g_arena || p.caplayer == 1 || g_lms)
s = GetPlayerScoreString(p, 2);
else
s = "-666";
ScoreRules_basics_end();
}
-// LMS stuff
-#define SP_LMS_LIVES 4
-#define SP_LMS_RANK 5
-void ScoreRules_lms()
-{
- ScoreRules_basics(0, 0, 0, FALSE);
- ScoreInfo_SetLabel_PlayerScore(SP_LMS_LIVES, "lives", SFL_SORT_PRIO_SECONDARY);
- ScoreInfo_SetLabel_PlayerScore(SP_LMS_RANK, "rank", SFL_LOWER_IS_BETTER | SFL_RANK | SFL_SORT_PRIO_PRIMARY | SFL_ALLOW_HIDE);
- ScoreRules_basics_end();
-}
-
// Key hunt stuff
#define ST_KH_CAPS 1
#define SP_KH_CAPS 4
ScoreRules_basics_end();
}
-// Assault stuff
-#define ST_ASSAULT_OBJECTIVES 1
-#define SP_ASSAULT_OBJECTIVES 4
-void ScoreRules_assault()
-{
- ScoreRules_basics(2, SFL_SORT_PRIO_SECONDARY, SFL_SORT_PRIO_SECONDARY, TRUE);
- ScoreInfo_SetLabel_TeamScore( ST_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY);
- ScoreInfo_SetLabel_PlayerScore(SP_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY);
- ScoreRules_basics_end();
-}
-
// Nexball stuff
#define ST_NEXBALL_GOALS 1
#define SP_NEXBALL_GOALS 4
skill = autocvar_skill;
- count_players();
- if(g_ca || g_freezetag)
- count_alive_players();
- Arena_Warmup();
- Spawnqueue_Check();
-
// detect when the pre-game countdown (if any) has ended and the game has started
game_delay = (time < game_starttime) ? TRUE : FALSE;
if(game_delay_last == TRUE)
if(game_delay == FALSE)
if(autocvar_sv_eventlog)
- GameLogEcho(":startdelay_ended");
+ GameLogEcho(":startdelay_ended");
game_delay_last = game_delay;
return TRUE;
if(autocvar_g_powerups == 0)
return FALSE;
- if(g_lms)
- return FALSE;
if(g_ca)
return FALSE;
if(g_arena)
return TRUE;
if(autocvar_g_pickup_items == 0)
return FALSE;
- if(g_lms)
- return FALSE;
if(g_ca)
return FALSE;
if(g_weaponarena)
if (clienttype(player) == CLIENTTYPE_REAL)
{
if(player.health <= 5)
- AnnounceTo(player, "lastsecond");
+ Send_Notification(NOTIF_ONE, player, MSG_ANNCE, ANNCE_MINSTAGIB_LASTSECOND);
else if(player.health < 50)
- AnnounceTo(player, "narrowly");
+ Send_Notification(NOTIF_ONE, player, MSG_ANNCE, ANNCE_MINSTAGIB_NARROWLY);
}
// sound not available
// else if(item.items == IT_CELLS)
// sound not available
// AnnounceTo(player, "_lives");
player.armorvalue = bound(player.armorvalue, 999, player.armorvalue + autocvar_g_minstagib_extralives);
- sprint(player, "^3You picked up some extra lives\n");
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_EXTRALIVES);
}
// invis powerup
leadlimit_override = 0; // not supported by LMS
if(fraglimit_override == 0)
fraglimit_override = -1;
- lms_lowest_lives = 9999;
- lms_next_place = 0;
- ScoreRules_lms();
+ MUTATOR_ADD(gamemode_lms);
}
if(g_arena)
{
fraglimit_override = autocvar_g_arena_point_limit;
leadlimit_override = autocvar_g_arena_point_leadlimit;
- maxspawned = autocvar_g_arena_maxspawned;
- if(maxspawned < 2)
- maxspawned = 2;
- arena_roundbased = autocvar_g_arena_roundbased;
+ MUTATOR_ADD(gamemode_arena);
}
if(g_ca)
ActivateTeamplay();
fraglimit_override = autocvar_g_ca_point_limit;
leadlimit_override = autocvar_g_ca_point_leadlimit;
- precache_sound("ctf/red_capture.wav");
- precache_sound("ctf/blue_capture.wav");
+ MUTATOR_ADD(gamemode_ca);
}
+
if(g_keyhunt)
{
ActivateTeamplay();
if(g_assault)
{
ActivateTeamplay();
- ScoreRules_assault();
+ MUTATOR_ADD(gamemode_assault);
have_team_spawns = -1; // request team spawns
}
self.effects = EF_NODRAW;
// Handle turret teams.
- if (autocvar_g_assault != 0)
- {
- if not (self.team)
- self.team = 14; // Assume turrets are on the defending side if not explicitly set otehrwize
- }
- else if not (teamplay)
+ if not (teamplay)
self.team = MAX_SHOT_DISTANCE; // Group all turrets into the same team, so they dont kill eachother.
else if(g_onslaught && self.targetname)
{
}
self.damage_flags |= TFL_DMG_HEADSHAKE;
+ self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK;
// Our fire routine
self.turret_firefunc = turret_machinegun_attack;
self.vehicle_exit = exitfunc;
self.vehicle_enter = enterproc;
self.PlayerPhysplug = physproc;
- self.event_damage = vehicles_damage;
+ self.event_damage = func_null;
self.touch = vehicles_touch;
self.think = vehicles_spawn;
self.nextthink = time;
self.vehicle_respawntime = _respawntime;
self.vehicle_spawn = spawnproc;
self.effects = EF_NODRAW;
- if(g_assault || !autocvar_g_vehicles_delayspawn)
+ if(!autocvar_g_vehicles_delayspawn)
self.nextthink = time + 0.5;
else
self.nextthink = time + _respawntime + (random() * autocvar_g_vehicles_delayspawn_jitter);
self.pos1 = self.origin;
self.pos2 = self.angles;
self.tur_head.team = self.team;
+
+ if(MUTATOR_CALLHOOK(VehicleSpawn))
+ return FALSE;
return TRUE;
}
.float dmg_force;
.float dmg_radius;
.float dmg_total;
+//.float last_yoda;
void W_BallisticBullet_Hit (void)
{
float f, q, g;
g = accuracy_isgooddamage(self.realowner, other);
Damage(other, self, self.realowner, self.dmg * f, self.projectiledeathtype, self.origin, self.dmg_force * normalize(self.velocity) * f);
- if(yoda)
- AnnounceTo(self.realowner, "awesome");
+ /*if(yoda && (time > (self.last_yoda + 5)))
+ {
+ Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
+ self.last_yoda = time;
+ }*/
// calculate hits for ballistic weapons
if(g)
if(IsDifferentTeam(self.realowner, other))
if(other.deadflag == DEAD_NO)
if(IsFlying(other))
- AnnounceTo(self.realowner, "electrobitch");
+ Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_ELECTROBITCH);
self.event_damage = func_null;
self.takedamage = DAMAGE_NO;
if(IsDifferentTeam(self.realowner, other))
if(other.deadflag == DEAD_NO)
if(IsFlying(other))
- AnnounceTo(self.realowner, "airshot");
+ Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
self.event_damage = func_null;
self.takedamage = DAMAGE_NO;
if(IsDifferentTeam(self.realowner, other))
if(other.deadflag == DEAD_NO)
if(IsFlying(other))
- AnnounceTo(self.realowner, "airshot");
+ Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
self.event_damage = func_null;
self.takedamage = DAMAGE_NO;
void W_Hagar_Attack2_Load (void)
{
// loadable hagar secondary attack, must always run each frame
+
+ if(time < game_starttime)
+ return;
float loaded, enough_ammo;
loaded = self.hagar_load >= autocvar_g_balance_hagar_secondary_load_max;
if(IsDifferentTeam(self.realowner, other))
if(other.deadflag == DEAD_NO)
if(IsFlying(other))
- AnnounceTo(self.realowner, "airshot");
+ Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
self.event_damage = func_null;
self.takedamage = DAMAGE_NO;
if(g_minstagib)
{
if(yoda)
- AnnounceTo(self, "yoda");
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
}
else
{
if(yoda && flying)
- AnnounceTo(self, "yoda");
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
if(damage_goodhits && self.minstanex_lasthit)
{
- AnnounceTo(self, "impressive");
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_ACHIEVEMENT_IMPRESSIVE);
damage_goodhits = 0; // only every second time
}
}
if (time < self.minstagib_nextthink)
return;
- if (self.deadflag || gameover)
+ if (self.deadflag || gameover || (self.flags & FL_GODMODE))
minstagib_stop_countdown(self);
else if (self.ammo_cells > 0 || (self.items & IT_UNLIMITED_WEAPON_AMMO))
{
+ if (self.minstagib_needammo)
+ self.health = 100;
minstagib_stop_countdown(self);
- self.health = 100;
}
else
{
if (self.health == 5)
{
Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
- AnnounceTo(self, "terminated");
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_MINSTAGIB_TERMINATED);
}
else if (self.health == 10)
{
Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
- AnnounceTo(self, "1");
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_1);
}
else if (self.health == 20)
{
Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
- AnnounceTo(self, "2");
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_2);
}
else if (self.health == 30)
{
Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
- AnnounceTo(self, "3");
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_3);
}
else if (self.health == 40)
{
Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
- AnnounceTo(self, "4");
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_4);
}
else if (self.health == 50)
{
Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
- AnnounceTo(self, "5");
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_5);
}
else if (self.health == 60)
{
Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
- AnnounceTo(self, "6");
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_6);
}
else if (self.health == 70)
{
Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
- AnnounceTo(self, "7");
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_7);
}
else if (self.health == 80)
{
Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
- AnnounceTo(self, "8");
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_8);
}
else if (self.health == 90)
{
Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MINSTA_FINDAMMO);
Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
- AnnounceTo(self, "9");
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_9);
}
else if (self.health == 100)
{
- Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MINSTA_FINDAMMO_FIRST);
+ Send_Notification(NOTIF_ONE_ONLY, self, MSG_MULTI, MULTI_MINSTA_FINDAMMO);
Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
- if not(self.flags & FL_GODMODE)
- AnnounceTo(self, "10");
}
}
self.minstagib_nextthink = time + 1;
FireRailgunBullet (w_shotorg, w_shotorg + w_shotdir * MAX_SHOT_DISTANCE, mydmg, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, WEP_NEX);
if(yoda && flying)
- AnnounceTo(self, "yoda");
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
//beam and muzzle flash done on client
SendCSQCNexBeamParticle(charge);
if(IsDifferentTeam(self.realowner, other))
if(other.deadflag == DEAD_NO)
if(IsFlying(other))
- AnnounceTo(self.realowner, "airshot");
+ Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
self.event_damage = func_null;
self.takedamage = DAMAGE_NO;
\g_pinata\Players will drop all weapons they possessed when they are killed
\g_weapon_stay\Weapons stay after they are picked up
\g_weaponarena\Selecting a weapon arena will give all players that weapon at spawn as well as unlimited ammo, and disable all other weapon pickups.
-\menu_weaponarena_with_laser\Also enable the laser in the weapon arena
\g_minstagib\Players will be given the Minstanex, which is a railgun with infinite damage. If the player runs out of ammo, he will have 10 seconds to find some or if he fails to do so, face death. The secondary fire mode is a laser which does not inflict any damage and is good for doing trickjumps.
\g_nix\No items Xonotic - instead of pickup items, everyone plays with the same weapon. After some time, a countdown will start, after which everyone will switch to another weapon.
\g_nix_with_laser\Always carry the laser as an additional weapon in Nix
\g_maplist_votable\Numero di mappe che sono mostrate nel voto delle mappe alla fine di una partita
\sv_vote_simple_majority_factor\La semplice maggioranza vince il voto
\XonoticMultiplayerDialog/Impostazioni avanzate...\Impostazioni avanzate del server
-\XonoticMultiplayerDialog/Mutatori...\Mutatori e arene dedicate ad armi
+\XonoticMultiplayerDialog/Mutatori...\Mutatori e arene di armi
\g_dodging\Abilita schivamento
\g_cloaked\Tutti i giocatori sono quasi invisibili
\g_footsteps\Abilita suoni dei passi
\g_pinata\I giocatori rilasceranno tutte le armi che possedevano appena vengono uccisi
\g_weapon_stay\Le armi rimangono dopo che vengono raccolte
\g_weaponarena\Selezionando un'arena dedicata ad un'arma si darà a tutti i giocatori quell'arma con munizioni infinite, e disabiliterà tutti gli altri raccoglimenti delle armi.
-\menu_weaponarena_with_laser\Abilita anche il laser nelle arene dedicate ad un'arma
\g_minstagib\Ai giocatori sarà dato il Minstanex, che è un railgun con danni illimitati. Se il giocatore rimane senza munizioni, avrà 10 secondi per trovarne alcune, altrimenti morirà. Il fuoco secondario è un laser che non infligge nessun danno ed è buono per effettuare vari trickjump.
\g_nix\"No items Xonotic" - invece di raccogliere oggetti, ognuno giocherà con la stessa arma. Dopo un pò di tempo, un conto alla rovescia inizierà, dopo il quale ognuno passerà ad un'altra arma.
\g_nix_with_laser\Porta sempre il laser come arma aggiuntiva nella modalità "No items Xonotic"
set g_turrets_unit_fusreac_std_ammo_max 100
set g_turrets_unit_fusreac_std_ammo 0
set g_turrets_unit_fusreac_std_ammo_recharge 100
+
+set g_turrets_unit_fusreac_std_shot_radius 0
+set g_turrets_unit_fusreac_std_shot_spread 0
+set g_turrets_unit_fusreac_std_shot_force 0
+set g_turrets_unit_fusreac_std_shot_volly 0
+set g_turrets_unit_fusreac_std_shot_volly_refire 0
+set g_turrets_unit_fusreac_std_target_range_optimal 0
+set g_turrets_unit_fusreac_std_target_select_rangebias 0
+set g_turrets_unit_fusreac_std_target_select_samebias 0
+set g_turrets_unit_fusreac_std_target_select_anglebias 0
+set g_turrets_unit_fusreac_std_target_select_playerbias 0
+set g_turrets_unit_fusreac_std_aim_firetolerance_dist 0
+set g_turrets_unit_fusreac_std_aim_speed 0
+set g_turrets_unit_fusreac_std_aim_maxrot 0
+set g_turrets_unit_fusreac_std_aim_maxpitch 0
+set g_turrets_unit_fusreac_std_track_type 0
+set g_turrets_unit_fusreac_std_track_accel_pitch 0
+set g_turrets_unit_fusreac_std_track_accel_rot 0
+set g_turrets_unit_fusreac_std_track_blendrate 0
\ No newline at end of file