From: Samual Lenks Date: Thu, 9 May 2013 20:47:52 +0000 (-0400) Subject: Merge remote-tracking branch 'origin/master' into cbrutail/hudlaserminsta_fix X-Git-Tag: xonotic-v0.7.0~55^2~6^2 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=commitdiff_plain;h=d0db4b5db11800d291fbdba93a67e8487fa033e2;hp=fcce97070612aebd8a1021e6662bbe2902786e02 Merge remote-tracking branch 'origin/master' into cbrutail/hudlaserminsta_fix --- diff --git a/_hud_common.cfg b/_hud_common.cfg index f4fa1c9427..15453b7dcc 100644 --- a/_hud_common.cfg +++ b/_hud_common.cfg @@ -10,6 +10,15 @@ seta hud_cursormode 1 "handle mouse input in cursor mode when CSQC displays a cu seta hud_fontsize 11 "text fontsize for the hud" seta hud_width 560 "2D virtual width for the hud" +seta hud_colorset_foreground_1 "2" "primary priority (important names, etc)" +seta hud_colorset_foreground_2 "3" "secondary priority (items, locations, numbers, etc)" +seta hud_colorset_foreground_3 "4" "tertiary priority or relatively inconsequential text" +seta hud_colorset_foreground_4 "1" "notice/attention grabbing texting" +seta hud_colorset_kill_1 "1" "'bad' or 'dangerous' text (death messages against you, kill notifications, etc)" +seta hud_colorset_kill_2 "3" "similar to above, but less important... OR, a highlight out of above message type" +seta hud_colorset_kill_3 "4" "'good' or 'beneficial' text (you fragging someone, etc)" +seta hud_colorset_background "7" "neutral/unimportant text" + // general hud panel cvars (i.e. shouldn't be adjusted by a skin config) seta hud_panel_weapons_ammo_full_shells 60 "show 100% of the status bar at this ammo count" seta hud_panel_weapons_ammo_full_nails 320 "show 100% of the status bar at this ammo count" @@ -35,6 +44,8 @@ alias -hud_panel_radar_maximized "cl_cmd hud radar 0" 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" @@ -92,4 +103,4 @@ seta hud_shownames_mindistance 1000 "start fading alpha/size at this distance" seta hud_shownames_maxdistance 5000 "alpha/size is 0 at this distance" seta hud_shownames_antioverlap 1 "if two tags get too close to each other, fade out the one further away from you" seta hud_shownames_antioverlap_distance 50 "2d distance to other tag after which to fade out" -seta hud_shownames_offset 52 "offset (along z-axis) tag from player origin by this many units" \ No newline at end of file +seta hud_shownames_offset 52 "offset (along z-axis) tag from player origin by this many units" diff --git a/_hud_descriptions.cfg b/_hud_descriptions.cfg index 90ae7a3743..9c7201d0ce 100644 --- a/_hud_descriptions.cfg +++ b/_hud_descriptions.cfg @@ -57,7 +57,7 @@ seta hud_panel_weapons_timeout_fadebgmin "" "minimum alpha of the panel backgrou seta hud_panel_weapons_timeout_fadefgmin "" "minimum alpha of the panel foreground while in effect mode 1" seta hud_panel_weapons_timeout_speed_in "" "speed that fading/moving onto the screen occurs" seta hud_panel_weapons_timeout_speed_out "" "speed that fading/moving off of the screen occurs" -seta hud_panel_weapons_label "" "1 = show number of weapon, 2 = show bound key of weapon" +seta hud_panel_weapons_label "" "1 = show number of weapon, 2 = show bound key of weapon, 3 = show name of weapon" seta hud_panel_weapons_accuracy "" "show accuracy color as the weapon icon background; colors can be configured with accuracy_color* cvars" seta hud_panel_weapons_ammo "" "show ammo as a status bar" seta hud_panel_weapons_onlyowned "" "show only owned weapons" @@ -126,7 +126,6 @@ seta hud_panel_notify_bg_border "" "if set to something else than \"\" = overrid seta hud_panel_notify_bg_padding "" "if set to something else than \"\" = override default padding of contents from border" seta hud_panel_notify_flip "" "order the list top to bottom instead of bottom to top" seta hud_panel_notify_fontsize "" "multiplier for the font size used for player names in the panel" -seta hud_panel_notify_print "" "also con_notify print the messages that are shown on the notify panel" seta hud_panel_notify_fadetime "" "fade out time" seta hud_panel_notify_time "" "time that a new entry stays until it fades out" @@ -200,7 +199,9 @@ seta hud_panel_modicons_bg_color_team "" "override panel color with team color i 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" diff --git a/balanceXPM.cfg b/balanceXPM.cfg index fc02dc9cb2..8012967ad7 100644 --- a/balanceXPM.cfg +++ b/balanceXPM.cfg @@ -475,10 +475,10 @@ set g_balance_crylink_reload_ammo 0 //default: 10 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 diff --git a/balanceXonotic.cfg b/balanceXonotic.cfg index a0252cb48b..c96ea21870 100644 --- a/balanceXonotic.cfg +++ b/balanceXonotic.cfg @@ -475,10 +475,10 @@ set g_balance_crylink_reload_ammo 0 //default: 10 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 diff --git a/commands.cfg b/commands.cfg index 413953df52..70ee53ecb0 100644 --- a/commands.cfg +++ b/commands.cfg @@ -56,11 +56,13 @@ alias who "qc_cmd_svcmd who ${* ?}" // Displa // generic commands (across all programs) alias addtolist "qc_cmd_svmenu addtolist ${* ?}" // Add a string to a cvar -alias qc_curl "qc_cmd_svmenu curl ${* ?}" // curl requests alias dumpcommands "qc_cmd_svmenu dumpcommands ${* ?}" // Dump all commands on the program to *_cmd_dump.txt +alias dumpnotifs "qc_cmd_svcl dumpnotifs ${* ?}" // Dump all notifications into notifications_dump.txt alias maplist "qc_cmd_svmenu maplist ${* ?}" // Automatic control of maplist -alias nextframe "qc_cmd_svmenu nextframe ${* ?}" // do something next frame +alias nextframe "qc_cmd_svmenu nextframe ${* ?}" // Execute the given command next frame of this VM +alias qc_curl "qc_cmd_svmenu qc_curl ${* ?}" // Queries a URL alias removefromlist "qc_cmd_svmenu removefromlist ${* ?}" // Remove a string from a cvar +alias restartnotifs "qc_cmd_svcl restartnotifs ${* ?}" // Re-initialize all notifications alias rpn "qc_cmd_svmenu rpn ${* ?}" // RPN calculator //alias settemp "qc_cmd_svmenu settemp ${* ?}" // Temporarily set a value to a cvar which is restored later //alias settemp_restore "qc_cmd_svmenu settemp_restore ${* ?}" // Restore all cvars set by settemp command diff --git a/defaultXonotic.cfg b/defaultXonotic.cfg index 4ea9639e5c..de83c9ae57 100644 --- a/defaultXonotic.cfg +++ b/defaultXonotic.cfg @@ -68,6 +68,12 @@ seta cl_spawnzoom_factor 2 "factor of zoom while spawning" seta cl_zoomfactor 5 "how much +zoom will zoom (1-16)" seta cl_zoomspeed 8 "how fast it will zoom (0.5-16), negative values mean instant zoom" seta cl_zoomsensitivity 0 "how zoom changes sensitivity (0 = weakest, 1 = strongest)" + +seta cl_unpress_zoom_on_spawn 1 "automatically unpress zoom when you spawn" +seta cl_unpress_zoom_on_death 1 "automatically unpress zoom when you die (and don't allow zoom again while dead)" +seta cl_unpress_zoom_on_weapon_switch 1 "automatically unpress zoom when you switch a weapon" +seta cl_unpress_attack_on_weapon_switch 1 "automatically unpress fire and fire1 attack buttons when you switch a weapon" + freelook 1 sensitivity 6 v_gamma 1 @@ -818,6 +824,7 @@ set g_chat_flood_lmax_tell 2 "private chat: maximum number of lines per chat mes set g_chat_flood_burst_tell 2 "private chat: allow bursts of so many chat lines" set g_chat_flood_notify_flooder 1 "when 0, the flooder still can see his own message" set g_chat_teamcolors 0 "colorize nicknames in team color for chat" +set g_chat_tellprivacy 1 "when disabled, tell messages are also sent to the server console log... otherwise they're kept private between players." set g_nick_flood_timeout 120 "time after which nick flood protection resets (set to 0 to disable nick flood checking)" set g_nick_flood_penalty 0.5 "duration of the nick flood penalty" set g_nick_flood_penalty_yellow 3 "number of changes to allow before warning and movement blocking" @@ -893,7 +900,7 @@ seta "userbind8_press" "say_team flag seen (l:%y^7); g_waypointsprite_team_here_ 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 @@ -940,6 +947,7 @@ con_chat 5 con_chatpos -9 con_chatsize 10 con_chatwidth 0.6 +con_notify 0 con_notifysize 10 con_notifyalign 0 @@ -981,8 +989,7 @@ seta menu_slist_showfull 1 "show servers even if they are full and have no slots 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" @@ -1345,6 +1352,9 @@ set r_showbboxes 0 // we REALLY need the end pos nudging DP bug workaround for trace-to-end-of-solid to work collision_endposnudge 1 +// FIXME remove this when the engine feature FINALLY MAYBE works +r_glsl_skeletal 0 + // animation tuning set cl_lerpanim_maxdelta_framegroups 0.05 // must be faster than fastest weapon refire set cl_lerpanim_maxdelta_server 0.1 // must be slower than slowest server controlled anim (e.g. animinfo stuff) @@ -1552,6 +1562,7 @@ exec turrets.cfg exec vehicles.cfg exec crosshairs.cfg exec gamemodes.cfg +exec notifications.cfg // load console command aliases and settings exec commands.cfg diff --git a/gamemodes.cfg b/gamemodes.cfg index 6cff7e5a42..b7e65c8eb8 100644 --- a/gamemodes.cfg +++ b/gamemodes.cfg @@ -26,7 +26,6 @@ alias cl_hook_gamestart_dm alias cl_hook_gamestart_tdm alias cl_hook_gamestart_dom alias cl_hook_gamestart_ctf -alias cl_hook_gamestart_rune alias cl_hook_gamestart_lms alias cl_hook_gamestart_arena alias cl_hook_gamestart_ca @@ -48,7 +47,6 @@ alias sv_hook_gamestart_dm alias sv_hook_gamestart_tdm alias sv_hook_gamestart_dom alias sv_hook_gamestart_ctf -alias sv_hook_gamestart_rune alias sv_hook_gamestart_lms alias sv_hook_gamestart_arena alias sv_hook_gamestart_ca @@ -79,8 +77,6 @@ seta g_arena_point_limit -1 "Arena point limit overriding the mapinfo specified seta g_arena_point_leadlimit -1 "Arena point lead limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)" seta g_domination_point_limit -1 "Domination point limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)" seta g_domination_point_leadlimit -1 "Domination point lead limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)" -seta g_runematch_point_limit -1 "Runematch point limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)" -seta g_runematch_point_leadlimit -1 "Runematch point lead limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)" seta g_keyhunt_point_limit -1 "Keyhunt point limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)" seta g_keyhunt_point_leadlimit -1 "Keyhunt point lead limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)" seta g_race_laps_limit -1 "Race laps limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)" @@ -105,9 +101,6 @@ set g_dom_weapon_stay 0 set g_lms_respawn_delay 0 set g_lms_respawn_waves 0 set g_lms_weapon_stay 0 -set g_rune_respawn_delay 0 -set g_rune_respawn_waves 0 -set g_rune_weapon_stay 0 set g_tdm_respawn_delay 0 set g_tdm_respawn_waves 0 set g_tdm_weapon_stay 0 @@ -149,6 +142,7 @@ set g_ft_weapon_stay 0 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" @@ -168,6 +162,9 @@ set g_ca_spectate_enemies 0 "Allow spectating enemy player by dead player during 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 + // ================== @@ -197,7 +194,6 @@ set g_ctf_flag_collect_delay 1 set g_ctf_flag_health 0 set g_ctf_flag_dropped_waypoint 2 "show dropped flag waypointsprite when a flag is lost. 1 = team only, 2 = for all players" set g_ctf_flag_dropped_floatinwater 200 "move upwards while in water at this velocity" -set g_ctf_flag_pickup_verbosename 0 "show the name of the person who picked up the flag too" set g_ctf_throw 1 "throwing allows circumventing carrierkill score, so enable this with care!" set g_ctf_throw_angle_max 90 "maximum upwards angle you can throw the flag" set g_ctf_throw_angle_min -90 "minimum downwards angle you can throw the flag" @@ -276,13 +272,17 @@ set g_domination_point_glow 0 "domination point glow (warning, slow)" // 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 // ========== @@ -341,9 +341,9 @@ set g_keyhunt_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_message "^1Don't camp!" set g_lms_campcheck_damage 100 set g_lms_campcheck_distance 1800 set g_lms_last_join 3 "if g_lms_join_anytime is false, new players can only join if the worst active player has more than (fraglimit - g_lms_last_join) lives" @@ -405,6 +405,11 @@ set g_onslaught_cp_health 1000 set g_onslaught_cp_buildhealth 100 set g_onslaught_cp_buildtime 5 set g_onslaught_cp_regen 20 +set g_onslaught_cp_proxydecap 0 "de-capture controlpoints by standing close to them" +set g_onslaught_cp_proxydecap_distance 512 +set g_onslaught_cp_proxydecap_dps 100 +set g_onslaught_spawn_at_controlpoints 0 +set g_onslaught_spawn_at_generator 0 // ====== @@ -414,61 +419,3 @@ set g_race 0 "Race: be faster than your opponents" set g_race_qualifying_timelimit 0 set g_race_qualifying_timelimit_override -1 set g_race_teams 0 "when 2, 3, or 4, the race is played as a team game (the team members can add up their laps)" - - -// =========== -// runematch -// =========== -set g_runematch 0 "Runematch: pick up and hold the runes, special items that give you points, a special power (rune) and a disadvantage (curse)" -set g_runematch_pointrate 5 -set g_runematch_fixedspawns 1 "use fixed runematch spawns if available" -set g_runematch_pointamt 1 -set g_runematch_shuffletime 30 "how often runes change position" -set g_runematch_respawntime 15 "how soon after being dropped to respawn" -set g_runematch_frags_killedby_runeholder 4 -set g_runematch_frags_killed_runeholder 5 -set g_runematch_frags_norune 0 -set g_runematch_drop_runes_max 2 "only drop up to 2 runes, the rest should respawn" -set g_runematch_allow_same 0 "allow matching rune-curse pairs" -set g_runematch_rune_alpha 0.78 -set g_runematch_rune_effects 544 "EF_ADDITIVE + EF_FULLBRIGHT = 544" -set g_runematch_rune_glow_size 0 -set g_runematch_rune_glow_color 0 -set g_runematch_rune_color_strength 1.0 -// strength/weakness -set g_balance_rune_strength_damage 2.0 -set g_balance_rune_strength_force 1.5 -set g_balance_curse_weak_damage 0.5 -set g_balance_curse_weak_force 0.6 -set g_balance_rune_strength_combo_damage 0.9 -set g_balance_rune_strength_combo_force 1.0 -// defense/vulner -set g_balance_rune_defense_takedamage 0.5 -set g_balance_curse_vulner_takedamage 2.0 -set g_balance_rune_defense_combo_takedamage 1.0 -// vampire/empathy -set g_balance_rune_vampire_absorb 0.4 -set g_balance_curse_empathy_takedamage -0.4 -set g_balance_rune_vampire_combo_absorb -0.1 -set g_balance_rune_vampire_maxhealth 500 -set g_balance_curse_empathy_minhealth 20 -set g_balance_rune_vampire_combo_minhealth 40 -// regen/venom -set g_balance_rune_regen_hpmod 1.75 -set g_balance_curse_venom_hpmod 0.6 -set g_balance_rune_regen_combo_hpmod 0.9 -set g_balance_rune_regen_regenrate 3.0 -set g_balance_curse_venom_rotrate 3.0 -set g_balance_rune_regen_combo_regenrate 0.5 -set g_balance_rune_regen_combo_rotrate 1.5 -set g_balance_rune_regen_limitmod 1 -set g_balance_curse_venom_limitmod 1 -set g_balance_rune_regen_combo_limitmod 1 -// speed/slow -set g_balance_rune_speed_atkrate 0.66 -set g_balance_curse_slow_atkrate 1.5 -set g_balance_rune_speed_combo_atkrate 1.2 -set g_balance_rune_speed_highspeed 1.5 -set g_balance_curse_slow_highspeed 0.6 -set g_balance_rune_speed_combo_highspeed 0.9 - diff --git a/gfx/hud/default/player_pink.tga b/gfx/hud/default/player_pink.tga new file mode 100644 index 0000000000..89a7659218 Binary files /dev/null and b/gfx/hud/default/player_pink.tga differ diff --git a/gfx/hud/default/player_yellow.tga b/gfx/hud/default/player_yellow.tga new file mode 100644 index 0000000000..8717d8f76d Binary files /dev/null and b/gfx/hud/default/player_yellow.tga differ diff --git a/gfx/menu/luminos/clearbutton_c.tga b/gfx/menu/luminos/clearbutton_c.tga new file mode 100644 index 0000000000..3de1ccb804 Binary files /dev/null and b/gfx/menu/luminos/clearbutton_c.tga differ diff --git a/gfx/menu/luminos/clearbutton_f.tga b/gfx/menu/luminos/clearbutton_f.tga new file mode 100644 index 0000000000..be0939c067 Binary files /dev/null and b/gfx/menu/luminos/clearbutton_f.tga differ diff --git a/gfx/menu/luminos/clearbutton_n.tga b/gfx/menu/luminos/clearbutton_n.tga new file mode 100644 index 0000000000..57d76c47e1 Binary files /dev/null and b/gfx/menu/luminos/clearbutton_n.tga differ diff --git a/gfx/menu/luminos/gametype_rune.tga b/gfx/menu/luminos/gametype_rune.tga deleted file mode 100644 index 6906411d39..0000000000 Binary files a/gfx/menu/luminos/gametype_rune.tga and /dev/null differ diff --git a/gfx/menu/luminos/skinvalues.txt b/gfx/menu/luminos/skinvalues.txt index 316ae273f8..e79dba0e09 100755 --- a/gfx/menu/luminos/skinvalues.txt +++ b/gfx/menu/luminos/skinvalues.txt @@ -189,6 +189,13 @@ COLOR_INPUTBOX_N '1 1 1' 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 diff --git a/gfx/menu/wickedx/clearbutton_c.tga b/gfx/menu/wickedx/clearbutton_c.tga new file mode 100644 index 0000000000..26bc0effef Binary files /dev/null and b/gfx/menu/wickedx/clearbutton_c.tga differ diff --git a/gfx/menu/wickedx/clearbutton_f.tga b/gfx/menu/wickedx/clearbutton_f.tga new file mode 100644 index 0000000000..e857381452 Binary files /dev/null and b/gfx/menu/wickedx/clearbutton_f.tga differ diff --git a/gfx/menu/wickedx/clearbutton_n.tga b/gfx/menu/wickedx/clearbutton_n.tga new file mode 100644 index 0000000000..26bc0effef Binary files /dev/null and b/gfx/menu/wickedx/clearbutton_n.tga differ diff --git a/gfx/menu/wickedx/gametype_rune.tga b/gfx/menu/wickedx/gametype_rune.tga deleted file mode 100644 index 6906411d39..0000000000 Binary files a/gfx/menu/wickedx/gametype_rune.tga and /dev/null differ diff --git a/gfx/menu/wickedx/skinvalues.txt b/gfx/menu/wickedx/skinvalues.txt index 3259d7122a..1560512858 100755 --- a/gfx/menu/wickedx/skinvalues.txt +++ b/gfx/menu/wickedx/skinvalues.txt @@ -189,6 +189,13 @@ COLOR_INPUTBOX_N '1 1 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 diff --git a/gfx/menu/xaw/clearbutton_c.tga b/gfx/menu/xaw/clearbutton_c.tga new file mode 100644 index 0000000000..d8bfea5adb Binary files /dev/null and b/gfx/menu/xaw/clearbutton_c.tga differ diff --git a/gfx/menu/xaw/clearbutton_f.tga b/gfx/menu/xaw/clearbutton_f.tga new file mode 100644 index 0000000000..338ac1f586 Binary files /dev/null and b/gfx/menu/xaw/clearbutton_f.tga differ diff --git a/gfx/menu/xaw/clearbutton_n.tga b/gfx/menu/xaw/clearbutton_n.tga new file mode 100644 index 0000000000..60ee8c8d10 Binary files /dev/null and b/gfx/menu/xaw/clearbutton_n.tga differ diff --git a/gfx/menu/xaw/gametype_rune.tga b/gfx/menu/xaw/gametype_rune.tga deleted file mode 100644 index 79c8f30b0d..0000000000 Binary files a/gfx/menu/xaw/gametype_rune.tga and /dev/null differ diff --git a/gfx/menu/xaw/skinvalues.txt b/gfx/menu/xaw/skinvalues.txt index 36db25d5cd..3bd555f031 100644 --- a/gfx/menu/xaw/skinvalues.txt +++ b/gfx/menu/xaw/skinvalues.txt @@ -129,6 +129,13 @@ COLOR_INPUTBOX_N '1 1 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 diff --git a/hud_luminos.cfg b/hud_luminos.cfg index 6a45b02a51..f99494a1cc 100644 --- a/hud_luminos.cfg +++ b/hud_luminos.cfg @@ -124,7 +124,6 @@ seta hud_panel_notify_bg_border "" seta hud_panel_notify_bg_padding "" seta hud_panel_notify_flip "0" seta hud_panel_notify_fontsize "0.8" -seta hud_panel_notify_print "1" seta hud_panel_notify_time "10" seta hud_panel_notify_fadetime "3" @@ -198,7 +197,9 @@ seta hud_panel_modicons_bg_color_team "" 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" diff --git a/hud_luminos_minimal.cfg b/hud_luminos_minimal.cfg index 7442f3bd72..bfa0c0b3e4 100644 --- a/hud_luminos_minimal.cfg +++ b/hud_luminos_minimal.cfg @@ -124,7 +124,6 @@ seta hud_panel_notify_bg_border "" seta hud_panel_notify_bg_padding "" seta hud_panel_notify_flip "1" seta hud_panel_notify_fontsize "0.8" -seta hud_panel_notify_print "0" seta hud_panel_notify_time "10" seta hud_panel_notify_fadetime "3" @@ -198,7 +197,9 @@ seta hud_panel_modicons_bg_color_team "" 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" diff --git a/hud_luminos_minimal_xhair.cfg b/hud_luminos_minimal_xhair.cfg index c4c99f317f..27ca9ab80d 100644 --- a/hud_luminos_minimal_xhair.cfg +++ b/hud_luminos_minimal_xhair.cfg @@ -124,7 +124,6 @@ seta hud_panel_notify_bg_border "" seta hud_panel_notify_bg_padding "" seta hud_panel_notify_flip "1" seta hud_panel_notify_fontsize "0.8" -seta hud_panel_notify_print "0" seta hud_panel_notify_time "10" seta hud_panel_notify_fadetime "3" @@ -198,7 +197,9 @@ seta hud_panel_modicons_bg_color_team "" 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" diff --git a/hud_luminos_old.cfg b/hud_luminos_old.cfg index 74d98c098d..3a489a04e4 100644 --- a/hud_luminos_old.cfg +++ b/hud_luminos_old.cfg @@ -124,7 +124,6 @@ seta hud_panel_notify_bg_border "" seta hud_panel_notify_bg_padding "" seta hud_panel_notify_flip "0" seta hud_panel_notify_fontsize "0.8" -seta hud_panel_notify_print "1" seta hud_panel_notify_time "10" seta hud_panel_notify_fadetime "3" @@ -198,7 +197,9 @@ seta hud_panel_modicons_bg_color_team "" 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" diff --git a/hud_nexuiz.cfg b/hud_nexuiz.cfg index ab326c6247..57053411d7 100644 --- a/hud_nexuiz.cfg +++ b/hud_nexuiz.cfg @@ -124,7 +124,6 @@ seta hud_panel_notify_bg_border "" seta hud_panel_notify_bg_padding "" seta hud_panel_notify_flip "0" seta hud_panel_notify_fontsize "1" -seta hud_panel_notify_print "1" seta hud_panel_notify_time "10" seta hud_panel_notify_fadetime "3" @@ -198,7 +197,9 @@ seta hud_panel_modicons_bg_color_team "" 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" diff --git a/models/player/erebus.iqm_0.txt b/models/player/erebus.iqm_0.txt index a7fc978538..3b8198a6d3 100644 --- a/models/player/erebus.iqm_0.txt +++ b/models/player/erebus.iqm_0.txt @@ -4,7 +4,10 @@ sex Male weight 105 age 26 bone_upperbody spine2 -bone_aim0 1 spine2 +bone_aim0 0.25 spine2 +bone_aim1 0.4 spine4 +bone_aim2 0.2 upperarm_L +bone_aim3 0.35 bip01 r hand bone_weapon bip01 r hand fixbone 1 diff --git a/models/player/gak.iqm_0.txt b/models/player/gak.iqm_0.txt index ba6faaed72..2f864a686e 100644 --- a/models/player/gak.iqm_0.txt +++ b/models/player/gak.iqm_0.txt @@ -4,7 +4,9 @@ sex Male weight 85 age 16 bone_upperbody spine2 -bone_aim0 1 spine2 +bone_aim0 0.25 spine2 +bone_aim1 0.4 spine4 +bone_aim2 0.35 bip01 r hand bone_weapon bip01 r hand fixbone 1 diff --git a/models/player/gakarmored.iqm_0.txt b/models/player/gakarmored.iqm_0.txt index c3096b387c..d561d64800 100644 --- a/models/player/gakarmored.iqm_0.txt +++ b/models/player/gakarmored.iqm_0.txt @@ -4,7 +4,9 @@ sex Male weight 90 age 20 bone_upperbody spine2 -bone_aim0 1 spine2 +bone_aim0 0.25 spine2 +bone_aim1 0.4 spine4 +bone_aim2 0.35 bip01 r hand bone_weapon bip01 r hand fixbone 1 diff --git a/models/player/gakmasked.iqm_0.txt b/models/player/gakmasked.iqm_0.txt index 796da05aab..10aeee8e16 100644 --- a/models/player/gakmasked.iqm_0.txt +++ b/models/player/gakmasked.iqm_0.txt @@ -4,7 +4,9 @@ sex Male weight 87 age 18 bone_upperbody spine2 -bone_aim0 1 spine2 +bone_aim0 0.25 spine2 +bone_aim1 0.4 spine4 +bone_aim2 0.35 bip01 r hand bone_weapon bip01 r hand fixbone 1 diff --git a/models/player/ignis.iqm_0.txt b/models/player/ignis.iqm_0.txt index 73035425be..6744e652a5 100644 --- a/models/player/ignis.iqm_0.txt +++ b/models/player/ignis.iqm_0.txt @@ -4,7 +4,10 @@ sex Male weight 88 age 31 bone_upperbody spine2 -bone_aim0 1 spine2 +bone_aim0 0.25 spine2 +bone_aim1 0.4 spine4 +bone_aim2 0.2 upperarm_L +bone_aim3 0.35 bip01 r hand bone_weapon bip01 r hand fixbone 1 diff --git a/models/player/ignishalfmasked.iqm_0.txt b/models/player/ignishalfmasked.iqm_0.txt index e0d82ea742..c956630f33 100644 --- a/models/player/ignishalfmasked.iqm_0.txt +++ b/models/player/ignishalfmasked.iqm_0.txt @@ -4,7 +4,10 @@ sex Male weight 90 age 31 bone_upperbody spine2 -bone_aim0 1 spine2 +bone_aim0 0.25 spine2 +bone_aim1 0.4 spine4 +bone_aim2 0.2 upperarm_L +bone_aim3 0.35 bip01 r hand bone_weapon bip01 r hand fixbone 1 diff --git a/models/player/ignismasked.iqm_0.txt b/models/player/ignismasked.iqm_0.txt index 3db94af41a..e89ead1dab 100644 --- a/models/player/ignismasked.iqm_0.txt +++ b/models/player/ignismasked.iqm_0.txt @@ -4,7 +4,10 @@ sex Male weight 92 age 31 bone_upperbody spine2 -bone_aim0 1 spine2 +bone_aim0 0.25 spine2 +bone_aim1 0.4 spine4 +bone_aim2 0.2 upperarm_L +bone_aim3 0.35 bip01 r hand bone_weapon bip01 r hand fixbone 1 diff --git a/models/player/megaerebus.iqm_0.txt b/models/player/megaerebus.iqm_0.txt index 4097c3b8b7..c2d811779c 100644 --- a/models/player/megaerebus.iqm_0.txt +++ b/models/player/megaerebus.iqm_0.txt @@ -4,7 +4,10 @@ sex Male weight 210 age 26 bone_upperbody spine2 -bone_aim0 1 spine2 +bone_aim0 0.25 spine2 +bone_aim1 0.4 spine4 +bone_aim2 0.2 upperarm_L +bone_aim3 0.35 bip01 r hand bone_weapon bip01 r hand fixbone 1 diff --git a/models/player/nyx.iqm_0.txt b/models/player/nyx.iqm_0.txt index 385546f123..50f41f35e5 100644 --- a/models/player/nyx.iqm_0.txt +++ b/models/player/nyx.iqm_0.txt @@ -4,7 +4,9 @@ sex Female weight 100 age 24 bone_upperbody spine2 -bone_aim0 1 spine2 +bone_aim0 0.25 spine2 +bone_aim1 0.4 spine4 +bone_aim2 0.35 bip01 r hand bone_weapon bip01 r hand fixbone 1 diff --git a/models/player/pyria.iqm_0.txt b/models/player/pyria.iqm_0.txt index f1abbd371a..489571a91a 100644 --- a/models/player/pyria.iqm_0.txt +++ b/models/player/pyria.iqm_0.txt @@ -4,7 +4,9 @@ sex Female weight 57 age 53 bone_upperbody spine2 -bone_aim0 1 spine2 +bone_aim0 0.25 spine2 +bone_aim1 0.4 spine4 +bone_aim2 0.35 bip01 r hand bone_weapon bip01 r hand fixbone 1 diff --git a/models/player/seraphina.iqm_0.txt b/models/player/seraphina.iqm_0.txt index 530f559e17..fc5a62b248 100644 --- a/models/player/seraphina.iqm_0.txt +++ b/models/player/seraphina.iqm_0.txt @@ -4,7 +4,9 @@ sex Female weight 89 age 31 bone_upperbody spine2 -bone_aim0 1 spine2 +bone_aim0 0.25 spine2 +bone_aim1 0.4 spine4 +bone_aim2 0.35 bip01 r hand bone_weapon bip01 r hand fixbone 1 diff --git a/models/player/seraphinamasked.iqm_0.txt b/models/player/seraphinamasked.iqm_0.txt index be15edbaf6..2a48e8d4e5 100644 --- a/models/player/seraphinamasked.iqm_0.txt +++ b/models/player/seraphinamasked.iqm_0.txt @@ -4,7 +4,9 @@ sex Female weight 90 age 31 bone_upperbody spine2 -bone_aim0 1 spine2 +bone_aim0 0.25 spine2 +bone_aim1 0.4 spine4 +bone_aim2 0.35 bip01 r hand bone_weapon bip01 r hand fixbone 1 diff --git a/models/player/umbra.iqm_0.txt b/models/player/umbra.iqm_0.txt index f20562a9f8..c5933c1ab6 100644 --- a/models/player/umbra.iqm_0.txt +++ b/models/player/umbra.iqm_0.txt @@ -4,7 +4,9 @@ sex Female weight 61 age 25 bone_upperbody spine2 -bone_aim0 1 spine2 +bone_aim0 0.25 spine2 +bone_aim1 0.4 spine4 +bone_aim2 0.35 bip01 r hand bone_weapon bip01 r hand fixbone 1 diff --git a/mutator_new_toys.cfg b/mutator_new_toys.cfg index 7b4a9ab9fa..07d349324e 100644 --- a/mutator_new_toys.cfg +++ b/mutator_new_toys.cfg @@ -107,7 +107,7 @@ set g_balance_rifle_reload_time 2 // }}} // {{{ seeker set g_balance_seeker_type 0 // 0 = old seeker, 1 = new seeker -set g_balance_seeker_flac_ammo 0.5 +set g_balance_seeker_flac_ammo 1 set g_balance_seeker_flac_animtime 0.1 set g_balance_seeker_flac_damage 15 set g_balance_seeker_flac_edgedamage 10 diff --git a/notifications.cfg b/notifications.cfg new file mode 100644 index 0000000000..1463d19b8f --- /dev/null +++ b/notifications.cfg @@ -0,0 +1,543 @@ +// ********************************************** // +// ** WARNING - DO NOT MANUALLY EDIT THIS FILE ** // +// ** ** // +// ** This file is automatically generated ** // +// ** by code with the command 'dumpnotifs'. ** // +// ** ** // +// ** If you add a new notification, please ** // +// ** regenerate this file with that command ** // +// ** making sure that the output matches ** // +// ** with the lists and defaults in code. ** // +// ** ** // +// ********************************************** // + +// 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_CTF_CAPTURE_BROKEN_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_TIME_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_TIME_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_UNBROKEN_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_UNBROKEN_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_FLAGRETURN_ABORTRUN_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_FLAGRETURN_ABORTRUN_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_FLAGRETURN_DAMAGED_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_FLAGRETURN_DAMAGED_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_FLAGRETURN_DROPPED_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_FLAGRETURN_DROPPED_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_FLAGRETURN_NEEDKILL_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_FLAGRETURN_NEEDKILL_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_FLAGRETURN_SPEEDRUN_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_FLAGRETURN_SPEEDRUN_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_FLAGRETURN_TIMEOUT_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_FLAGRETURN_TIMEOUT_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_LOST_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_LOST_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_PICKUP_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_PICKUP_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_RETURN_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_RETURN_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_DEATH_MURDER_CHEAT "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_DEATH_MURDER_DROWN "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_DEATH_MURDER_FALL "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_DEATH_MURDER_FIRE "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_DEATH_MURDER_LAVA "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_DEATH_MURDER_SHOOTING_STAR "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_DEATH_MURDER_SLIME "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_DEATH_MURDER_SWAMP "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_DEATH_MURDER_TELEFRAG "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_DEATH_MURDER_TOUCHEXPLODE "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_DEATH_MURDER_VH_BUMB_DEATH "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_DEATH_MURDER_VH_BUMB_GUN "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_DEATH_MURDER_VH_CRUSH "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_DEATH_MURDER_VH_RAPT_BOMB "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_DEATH_MURDER_VH_RAPT_CANNON "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_DEATH_MURDER_VH_RAPT_DEATH "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_DEATH_MURDER_VH_SPID_DEATH "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_DEATH_MURDER_VH_SPID_MINIGUN "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_DEATH_MURDER_VH_SPID_ROCKET "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_DEATH_MURDER_VH_WAKI_DEATH "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_DEATH_MURDER_VH_WAKI_GUN "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_DEATH_MURDER_VH_WAKI_ROCKET "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_DEATH_MURDER_VOID "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_DEATH_SELF_AUTOTEAMCHANGE "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_DEATH_SELF_BETRAYAL "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_DEATH_SELF_CAMP "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_DEATH_SELF_CHEAT "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_DEATH_SELF_CUSTOM "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_DEATH_SELF_DROWN "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_DEATH_SELF_FALL "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_DEATH_SELF_FIRE "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_DEATH_SELF_GENERIC "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_DEATH_SELF_LAVA "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_DEATH_SELF_NOAMMO "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_DEATH_SELF_ROT "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_DEATH_SELF_SHOOTING_STAR "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_DEATH_SELF_SLIME "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_DEATH_SELF_SUICIDE "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_DEATH_SELF_SWAMP "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_DEATH_SELF_TEAMCHANGE "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_DEATH_SELF_TOUCHEXPLODE "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_DEATH_SELF_TURRET "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_DEATH_SELF_TURRET_EWHEEL "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_DEATH_SELF_TURRET_FLAC "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_DEATH_SELF_TURRET_HELLION "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_DEATH_SELF_TURRET_HK "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_DEATH_SELF_TURRET_MACHINEGUN "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_DEATH_SELF_TURRET_MLRS "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_DEATH_SELF_TURRET_PHASER "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_DEATH_SELF_TURRET_PLASMA "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_DEATH_SELF_TURRET_TESLA "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_DEATH_SELF_TURRET_WALK_GUN "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_DEATH_SELF_TURRET_WALK_MEELE "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_DEATH_SELF_TURRET_WALK_ROCKET "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_DEATH_SELF_VH_BUMB_DEATH "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_DEATH_SELF_VH_CRUSH "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_DEATH_SELF_VH_RAPT_BOMB "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_DEATH_SELF_VH_RAPT_DEATH "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_DEATH_SELF_VH_SPID_DEATH "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_DEATH_SELF_VH_SPID_ROCKET "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_DEATH_SELF_VH_WAKI_DEATH "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_DEATH_SELF_VH_WAKI_ROCKET "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_DEATH_SELF_VOID "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_DEATH_TEAMKILL_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_DEATH_TEAMKILL_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_DEATH_TEAMKILL_YELLOW "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_DEATH_TEAMKILL_PINK "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_FREEZETAG_FREEZE "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_FREEZETAG_REVIVE "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_FREEZETAG_ROUND_WIN_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_FREEZETAG_ROUND_WIN_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_FREEZETAG_ROUND_WIN_YELLOW "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_FREEZETAG_ROUND_WIN_PINK "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_FREEZETAG_SELF "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_GODMODE_OFF "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_ITEM_WEAPON_DONTHAVE "0" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)" +seta notification_INFO_ITEM_WEAPON_DROP "0" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)" +seta notification_INFO_ITEM_WEAPON_GOT "0" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)" +seta notification_INFO_ITEM_WEAPON_NOAMMO "0" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)" +seta notification_INFO_ITEM_WEAPON_PRIMORSEC "0" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)" +seta notification_INFO_ITEM_WEAPON_UNAVAILABLE "0" "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 "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_RED "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_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 "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_KEYHUNT_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_KEYHUNT_CAPTURE_YELLOW "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_PINK "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_DROP_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_KEYHUNT_DROP_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_KEYHUNT_DROP_YELLOW "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_DROP_PINK "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_LOST_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_KEYHUNT_LOST_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_KEYHUNT_LOST_YELLOW "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_LOST_PINK "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_PICKUP_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_KEYHUNT_PICKUP_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_KEYHUNT_PICKUP_YELLOW "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_PICKUP_PINK "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_LMS_FORFEIT "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_LMS_NOLIVES "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_POWERUP_INVISIBILITY "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_POWERUP_SHIELD "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_POWERUP_SPEED "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_POWERUP_STRENGTH "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 "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_RACE_FINISHED "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_NEW_BROKEN "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_NEW_IMPROVED "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_NEW_MISSING_UID "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_NEW_SET "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_SCORES_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_SCORES_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_SCORES_YELLOW "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_SCORES_PINK "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_SPECTATE_WARNING "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_SUPERWEAPON_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_VERSION_BETA "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_VERSION_OLD "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_VERSION_OUTDATED "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_WATERMARK "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_ACCORDEON_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_ACCORDEON_SUICIDE "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_CRYLINK_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_CRYLINK_SUICIDE "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_ELECTRO_MURDER_BOLT "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_ELECTRO_MURDER_COMBO "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_ELECTRO_MURDER_ORBS "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_ELECTRO_SUICIDE_BOLT "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_ELECTRO_SUICIDE_ORBS "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_FIREBALL_MURDER_BLAST "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_FIREBALL_MURDER_FIREMINE "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_FIREBALL_SUICIDE_BLAST "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_FIREBALL_SUICIDE_FIREMINE "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_HAGAR_MURDER_BURST "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_HAGAR_MURDER_SPRAY "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_HAGAR_SUICIDE "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_HLAC_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_HLAC_SUICIDE "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_HOOK_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_KLEINBOTTLE_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_KLEINBOTTLE_SUICIDE "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_LASER_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_LASER_SUICIDE "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_MINELAYER_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_MINELAYER_SUICIDE "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_MINSTANEX_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_MORTAR_MURDER_BOUNCE "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_MORTAR_MURDER_EXPLODE "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_MORTAR_SUICIDE_BOUNCE "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_MORTAR_SUICIDE_EXPLODE "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_NEX_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 "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_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_INFO_WEAPON_ROCKETLAUNCHER_SUICIDE "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_SEEKER_MURDER_SPRAY "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_SEEKER_MURDER_TAG "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_SEEKER_SUICIDE "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_SHOTGUN_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_SHOTGUN_MURDER_SLAP "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_THINKING_WITH_PORTALS "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_TUBA_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_TUBA_SUICIDE "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_UZI_MURDER_SNIPE "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_UZI_MURDER_SPRAY "1" "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)" + +// MSG_CENTER notifications (count = 133): +seta notification_CENTER_ARENA_BEGIN "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_ARENA_NEEDPLAYER "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_ARENA_ROUNDSTART "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_ASSAULT_ATTACKING "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_ASSAULT_DEFENDING "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_COUNTDOWN_BEGIN "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_COUNTDOWN_GAMESTART "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_CAPTURESHIELD_FREE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_CAPTURESHIELD_SHIELDED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_CAPTURE_RED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_CAPTURE_BLUE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_FLAG_THROW_PUNISH "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_PASS_OTHER_RED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_PASS_OTHER_BLUE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_PASS_RECEIVED_RED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_PASS_RECEIVED_BLUE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_PASS_REQUESTED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_PASS_REQUESTING "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_PASS_SENT_RED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_PASS_SENT_BLUE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_PICKUP_RED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_PICKUP_BLUE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_PICKUP_ENEMY "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_PICKUP_ENEMY_VERBOSE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_PICKUP_TEAM "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_PICKUP_TEAM_VERBOSE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_RETURN_RED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_RETURN_BLUE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_STALEMATE_CARRIER "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_CTF_STALEMATE_OTHER "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_MURDER_FRAG "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_MURDER_FRAGGED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_MURDER_FRAGGED_VERBOSE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_MURDER_FRAG_VERBOSE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_MURDER_TYPEFRAG "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_MURDER_TYPEFRAGGED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_AUTOTEAMCHANGE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_BETRAYAL "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_CAMP "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_CHEAT "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_CUSTOM "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_DROWN "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_FALL "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_FIRE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_GENERIC "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_LAVA "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_NOAMMO "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_ROT "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_SHOOTING_STAR "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_SLIME "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_SUICIDE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_SWAMP "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_TEAMCHANGE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_TOUCHEXPLODE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_TURRET "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_TURRET_EWHEEL "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_TURRET_WALK "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_VH_BUMB_DEATH "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_VH_CRUSH "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_VH_RAPT_BOMB "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_VH_RAPT_DEATH "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_VH_SPID_DEATH "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_VH_SPID_ROCKET "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_VH_WAKI_DEATH "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_VH_WAKI_ROCKET "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_SELF_VOID "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_TEAMKILL_FRAG "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DEATH_TEAMKILL_FRAGGED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_DISCONNECT_IDLING "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_FREEZETAG_FREEZE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_FREEZETAG_FROZEN "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_FREEZETAG_REVIVE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_FREEZETAG_REVIVED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_FREEZETAG_ROUND_WIN_RED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_FREEZETAG_ROUND_WIN_BLUE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_FREEZETAG_ROUND_WIN_YELLOW "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_FREEZETAG_ROUND_WIN_PINK "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_FREEZETAG_SELF "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_FREEZETAG_SPAWN_LATE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_ITEM_WEAPON_DONTHAVE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_ITEM_WEAPON_DROP "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_ITEM_WEAPON_GOT "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_ITEM_WEAPON_NOAMMO "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_ITEM_WEAPON_PRIMORSEC "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_ITEM_WEAPON_UNAVAILABLE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_JOIN_NOSPAWNS "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_JOIN_PREVENT "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEEPAWAY_DROPPED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEEPAWAY_PICKUP "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEEPAWAY_WARN "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEYHUNT_HELP "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEYHUNT_INTERFERE_RED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEYHUNT_INTERFERE_BLUE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEYHUNT_INTERFERE_YELLOW "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEYHUNT_INTERFERE_PINK "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEYHUNT_MEET "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEYHUNT_SCAN "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEYHUNT_START_RED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEYHUNT_START_BLUE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEYHUNT_START_YELLOW "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEYHUNT_START_PINK "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_KEYHUNT_WAIT "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_LMS_CAMPCHECK "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_MINSTA_FINDAMMO "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_MINSTA_FINDAMMO_FIRST "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_MOTD "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_NIX_COUNTDOWN "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_NIX_NEWWEAPON "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_OVERTIME_FRAG "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_OVERTIME_TIME "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_POWERDOWN_INVISIBILITY "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_POWERDOWN_SHIELD "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_POWERDOWN_SPEED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_POWERDOWN_STRENGTH "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_POWERUP_INVISIBILITY "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_POWERUP_SHIELD "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_POWERUP_SPEED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_POWERUP_STRENGTH "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_RACE_FINISHLAP "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_SUPERWEAPON_BROKEN "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_SUPERWEAPON_LOST "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_SUPERWEAPON_PICKUP "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_TEAMCHANGE_RED "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_TEAMCHANGE_BLUE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_TEAMCHANGE_YELLOW "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_TEAMCHANGE_PINK "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_TEAMCHANGE_AUTO "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_TEAMCHANGE_SPECTATE "1" "Notification control cvar: 0 = off, 1 = centerprint" +seta notification_CENTER_TEAMCHANGE_SUICIDE "1" "Notification control cvar: 0 = off, 1 = centerprint" +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 = 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_DEATH_MURDER_FIRE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_LAVA "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_SHOOTING_STAR "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_SLIME "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_SWAMP "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_TELEFRAG "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_TOUCHEXPLODE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_VH_BUMB_DEATH "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_VH_BUMB_GUN "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_VH_CRUSH "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_VH_RAPT_BOMB "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_VH_RAPT_CANNON "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_VH_RAPT_DEATH "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_VH_SPID_DEATH "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_VH_SPID_MINIGUN "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_VH_SPID_ROCKET "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_VH_WAKI_DEATH "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_VH_WAKI_GUN "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_VH_WAKI_ROCKET "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_MURDER_VOID "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_AUTOTEAMCHANGE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_BETRAYAL "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_CAMP "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_CHEAT "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_CUSTOM "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_DROWN "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_FALL "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_FIRE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_GENERIC "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_LAVA "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_NOAMMO "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_ROT "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_SHOOTING_STAR "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_SLIME "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_SUICIDE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_SWAMP "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TEAMCHANGE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TOUCHEXPLODE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TURRET "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TURRET_EWHEEL "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TURRET_FLAC "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TURRET_HELLION "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TURRET_HK "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TURRET_MACHINEGUN "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TURRET_MLRS "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TURRET_PHASER "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TURRET_PLASMA "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TURRET_TESLA "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TURRET_WALK_GUN "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TURRET_WALK_MEELE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_TURRET_WALK_ROCKET "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_VH_BUMB_DEATH "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_VH_CRUSH "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_VH_RAPT_BOMB "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_VH_RAPT_DEATH "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_VH_SPID_DEATH "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_VH_SPID_ROCKET "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_VH_WAKI_DEATH "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_VH_WAKI_ROCKET "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_DEATH_SELF_VOID "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_ITEM_WEAPON_DONTHAVE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_ITEM_WEAPON_DROP "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_ITEM_WEAPON_GOT "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_CRYLINK_SUICIDE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_ELECTRO_MURDER_BOLT "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_ELECTRO_MURDER_COMBO "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_ELECTRO_MURDER_ORBS "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_ELECTRO_SUICIDE_BOLT "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_ELECTRO_SUICIDE_ORBS "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_FIREBALL_MURDER_BLAST "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_FIREBALL_MURDER_FIREMINE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_FIREBALL_SUICIDE_BLAST "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_FIREBALL_SUICIDE_FIREMINE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_HAGAR_MURDER_BURST "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_HAGAR_MURDER_SPRAY "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_HAGAR_SUICIDE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_HLAC_MURDER "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_HLAC_SUICIDE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_HOOK_MURDER "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_KLEINBOTTLE_MURDER "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_KLEINBOTTLE_SUICIDE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_LASER_MURDER "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_LASER_SUICIDE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_MINELAYER_MURDER "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_MINELAYER_SUICIDE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_MINSTANEX_MURDER "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_MORTAR_MURDER_BOUNCE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_MORTAR_MURDER_EXPLODE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_MORTAR_SUICIDE_BOUNCE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_MORTAR_SUICIDE_EXPLODE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_NEX_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_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_WEAPON_ROCKETLAUNCHER_SUICIDE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_SEEKER_MURDER_SPRAY "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_SEEKER_MURDER_TAG "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_SEEKER_SUICIDE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_SHOTGUN_MURDER "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_SHOTGUN_MURDER_SLAP "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_THINKING_WITH_PORTALS "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_TUBA_MURDER "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_TUBA_SUICIDE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_UZI_MURDER_SNIPE "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" +seta notification_WEAPON_UZI_MURDER_SPRAY "1" "Notification control cvar: 0 = off, 1 = trigger subcalls" + +// HARD CODED notification variables: +seta notification_allow_chatboxprint "1" "Allow notifications to be printed to chat box by setting notification cvar to 2 (You can also set this cvar to 2 to force ALL notifications to be printed to the chatbox)" +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_lifetime_mapload "10" "Amount of time that notification entities last immediately at mapload (in seconds) to help prevent notifications from being lost on early init (like gamestart countdown)" +seta notification_lifetime_runtime "0.5" "Amount of time that notification entities last on the server during runtime (In seconds)" +seta notification_server_allows_frag_verbose "1" "Server side cvar for showing extra information in frag messages... 0 = no extra frag information, 1 = frag information only in warmup, 2 = frag information allowed all the time" +seta notification_server_allows_location "1" "Server side cvar for allowing death messages to show location information too" +seta notification_show_location "0" "Append location information to MSG_INFO death/kill messages" +seta notification_show_location_string "" "Replacement string piped into sprintf, so you can do different messages like this: ' at the %s' or ' (near %s)'" +seta notification_show_sprees "1" "Print information about sprees in death/kill messages" +seta notification_show_sprees_center "1" "Show spree information in MSG_CENTER messages... 0 = off, 1 = target (but only for first victim) and attacker" +seta notification_show_sprees_center_specialonly "1" "Don't show spree information in MSG_CENTER messages if it isn't an achievement" +seta notification_show_sprees_info "3" "Show spree information in MSG_INFO messages... 0 = off, 1 = target only, 2 = attacker only, 3 = target and attacker" +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 = 499): MSG_ANNCE = 39, MSG_INFO = 207, MSG_CENTER = 133, MSG_MULTI = 120 diff --git a/qcsrc/Makefile b/qcsrc/Makefile index 5d079dcb05..4f772589ba 100644 --- a/qcsrc/Makefile +++ b/qcsrc/Makefile @@ -33,6 +33,8 @@ QCCFLAGS ?= \ -floop-labels \ -funtyped-nil \ -fno-permissive \ + -fvariadic-args \ + -DNOTIFICATIONS_DEBUG \ $(QCCFLAGS_EXTRA) $(QCCFLAGS_WATERMARK) else # this. is. fteqccccccccccccccccccc! diff --git a/qcsrc/client/Defs.qc b/qcsrc/client/Defs.qc index d65c517a30..b89a177f04 100644 --- a/qcsrc/client/Defs.qc +++ b/qcsrc/client/Defs.qc @@ -248,7 +248,6 @@ vector angles_held; .float silent; float w_deathtype, w_issilent, w_random; -string w_deathtypestring; vector w_org, w_backoff; float rifle_scope; diff --git a/qcsrc/client/Main.qc b/qcsrc/client/Main.qc index d7f65c6ecd..7a11300ea9 100644 --- a/qcsrc/client/Main.qc +++ b/qcsrc/client/Main.qc @@ -149,11 +149,14 @@ void CSQC_Init(void) teams = Sort_Spawn(); players = Sort_Spawn(); - GetTeam(COLOR_SPECTATOR, true); // add specs first + GetTeam(NUM_SPECTATOR, true); // add specs first // needs to be done so early because of the constants they create CALL_ACCUMULATED_FUNCTION(RegisterWeapons); CALL_ACCUMULATED_FUNCTION(RegisterGametypes); + CALL_ACCUMULATED_FUNCTION(RegisterNotifications); + CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); + CALL_ACCUMULATED_FUNCTION(RegisterHUD_Panels); WaypointSprite_Load(); @@ -177,7 +180,6 @@ void CSQC_Init(void) DamageInfo_Precache(); Vehicles_Precache(); turrets_precache(); - Announcer_Precache(); Tuba_Precache(); CSQCPlayer_Precache(); @@ -209,7 +211,6 @@ void CSQC_Init(void) 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"))); } @@ -261,16 +262,16 @@ float SetTeam(entity o, float Team) switch(Team) { case -1: - case COLOR_TEAM1: - case COLOR_TEAM2: - case COLOR_TEAM3: - case COLOR_TEAM4: + case NUM_TEAM_1: + case NUM_TEAM_2: + case NUM_TEAM_3: + case NUM_TEAM_4: break; default: if(GetTeam(Team, false) == world) { print(sprintf(_("trying to switch to unsupported team %d\n"), Team)); - Team = COLOR_SPECTATOR; + Team = NUM_SPECTATOR; } break; } @@ -286,7 +287,7 @@ float SetTeam(entity o, float Team) if(GetTeam(Team, false) == world) { print(sprintf(_("trying to switch to unsupported team %d\n"), Team)); - Team = COLOR_SPECTATOR; + Team = NUM_SPECTATOR; } break; } @@ -779,7 +780,8 @@ void CSQC_Ent_Update(float bIsNewEntity) case ENT_CLIENT_TURRET: ent_turret(); break; case ENT_CLIENT_MODEL: CSQCModel_Read(bIsNewEntity); break; case ENT_CLIENT_ITEM: ItemRead(bIsNewEntity); break; - case ENT_CLIENT_BUMBLE_RAYGUN: bumble_raygun_read(bIsNewEntity); break; + case ENT_CLIENT_BUMBLE_RAYGUN: bumble_raygun_read(bIsNewEntity); break; + case ENT_CLIENT_NOTIFICATION: Read_Notification(bIsNewEntity); break; default: //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype)); error(sprintf(_("Unknown entity type in CSQC_Ent_Update (enttype: %d, edict: %d, classname: %s)\n"), self.enttype, num_for_edict(self), self.classname)); @@ -1103,6 +1105,12 @@ void Net_ReadSpawn() { zoomin_effect = 1; current_viewzoom = (1 / bound(1, autocvar_cl_spawnzoom_factor, 16)); + + if(autocvar_cl_unpress_zoom_on_spawn) + { + localcmd("-zoom\n"); + button_zoom = FALSE; + } } void Net_TeamNagger() @@ -1124,7 +1132,8 @@ void Net_ReadPingPLReport() playerslots[e].ping_movementloss = ml / 255.0; } -void Net_WeaponComplain() { +void Net_WeaponComplain() +{ complain_weapon = ReadByte(); if(complain_weapon_name) @@ -1135,6 +1144,13 @@ void Net_WeaponComplain() { complain_weapon_time = time; weapontime = time; // ping the weapon panel + + switch(complain_weapon_type) + { + case 0: Local_Notification(MSG_MULTI, ITEM_WEAPON_NOAMMO, complain_weapon); break; + case 1: Local_Notification(MSG_MULTI, ITEM_WEAPON_DONTHAVE, complain_weapon); break; + default: Local_Notification(MSG_MULTI, ITEM_WEAPON_UNAVAILABLE, complain_weapon); break; + } } // CSQC_Parse_TempEntity : Handles all temporary entity network data in the CSQC layer. @@ -1190,29 +1206,6 @@ float CSQC_Parse_TempEntity() Net_ReadPingPLReport(); bHandled = true; break; - case TE_CSQC_ANNOUNCE: - Announcer_Play(ReadString()); - bHandled = true; - break; - case TE_CSQC_KILLNOTIFY: - HUD_KillNotify(ReadString(), ReadString(), ReadString(), ReadShort(), ReadByte()); - bHandled = true; - break; - case TE_CSQC_KILLCENTERPRINT: - HUD_KillCenterprint(ReadString(), ReadString(), ReadShort(), ReadByte()); - bHandled = true; - break; - case TE_CSQC_CENTERPRINT_GENERIC: - float id; - string s; - id = ReadByte(); - s = ReadString(); - if (id != 0 && s != "") - centerprint_generic(id, s, ReadByte(), ReadByte()); - else - centerprint_generic(id, s, 0, 0); - bHandled = true; - break; case TE_CSQC_WEAPONCOMPLAIN: Net_WeaponComplain(); bHandled = true; diff --git a/qcsrc/client/View.qc b/qcsrc/client/View.qc index dac205e723..d27fd4d98e 100644 --- a/qcsrc/client/View.qc +++ b/qcsrc/client/View.qc @@ -249,7 +249,7 @@ float EnemyHitCheck() if(teamplay) if(t == myteam) return SHOTTYPE_HITTEAM; - if(t == COLOR_SPECTATOR) + if(t == NUM_SPECTATOR) return SHOTTYPE_HITWORLD; return SHOTTYPE_HITENEMY; } @@ -384,6 +384,7 @@ float checkfail[16]; #define BUTTON_3 4 #define BUTTON_4 8 float cl_notice_run(); +float prev_myteam; void CSQC_UpdateView(float w, float h) { entity e; @@ -414,13 +415,6 @@ void CSQC_UpdateView(float w, float h) button_attack2 = (input_buttons & BUTTON_3); button_zoom = (input_buttons & BUTTON_4); - // FIXME do we need this hack? - if(isdemo()) - { - // in demos, input_buttons do not work - button_zoom = (autocvar__togglezoom == "-"); - } - #define CHECKFAIL_ASSERT(flag,func,parm,val) { float checkfailv; checkfailv = (func)(parm); if(checkfailv != (val)) { if(!checkfail[(flag)]) localcmd(sprintf("\ncmd checkfail %s %s %d %d\n", #func, parm, val, checkfailv)); checkfail[(flag)] = 1; } } ENDS_WITH_CURLY_BRACE CHECKFAIL_ASSERT(0, cvar_type, "\{100}\{105}\{118}\{48}\{95}\{101}\{118}\{97}\{100}\{101}", 0); CHECKFAIL_ASSERT(1, cvar_type, "\{97}\{97}\{95}\{101}\{110}\{97}\{98}\{108}\{101}", 0); @@ -449,12 +443,38 @@ void CSQC_UpdateView(float w, float h) #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); + + // FIXME do we need this hack? + if(isdemo()) + { + // in demos, input_buttons do not work + button_zoom = (autocvar__togglezoom == "-"); + } + else if(button_zoom + && autocvar_cl_unpress_zoom_on_death + && (spectatee_status >= 0) + && (is_dead || intermission)) + { + // no zoom while dead or in intermission please + localcmd("-zoom\n"); + button_zoom = FALSE; + } + // event chase camera if(autocvar_chase_active <= 0) // greater than 0 means it's enabled manually, and this code is skipped { - if(spectatee_status >= 0 && (autocvar_cl_eventchase_death && getstati(STAT_HEALTH) <= 0 && !intermission) || intermission) + if(spectatee_status >= 0 && (autocvar_cl_eventchase_death && is_dead) || intermission) { // make special vector since we can't use view_origin (It is one frame old as of this code, it gets set later with the results this code makes.) vector current_view_origin = ((csqcplayer ? csqcplayer.origin : pmove_org) + autocvar_cl_eventchase_viewoffset); @@ -604,11 +624,24 @@ void CSQC_UpdateView(float w, float h) HUD_InitScores(); } - if(last_switchweapon != switchweapon) { + if(last_switchweapon != switchweapon) + { weapontime = time; last_switchweapon = switchweapon; + if(button_zoom && autocvar_cl_unpress_zoom_on_weapon_switch) + { + localcmd("-zoom\n"); + button_zoom = FALSE; + } + if(autocvar_cl_unpress_attack_on_weapon_switch) + { + localcmd("-fire\n"); + localcmd("-fire2\n"); + button_attack2 = FALSE; + } } - if(last_activeweapon != activeweapon) { + if(last_activeweapon != activeweapon) + { last_activeweapon = activeweapon; e = get_weaponinfo(activeweapon); @@ -756,7 +789,7 @@ void CSQC_UpdateView(float w, float h) // reticle_type is changed to the item we are zooming / aiming with, to decide which reticle to use // It must be a persisted float for fading out to work properly (you let go of the zoom button for // the view to go back to normal, so reticle_type would become 0 as we fade out) - if(spectatee_status || getstati(STAT_HEALTH) <= 0 || hud != HUD_NORMAL) + if(spectatee_status || is_dead || hud != HUD_NORMAL) reticle_type = 0; // prevent reticle from showing during the respawn zoom effect or for spectators else if(activeweapon == WEP_NEX && (button_zoom || zoomscript_caught) || activeweapon == WEP_RIFLE && (button_zoom || zoomscript_caught) || activeweapon == WEP_MINSTANEX && (button_zoom || zoomscript_caught)) reticle_type = 2; // nex zoom @@ -862,8 +895,8 @@ void CSQC_UpdateView(float w, float h) } } } - - 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); @@ -1047,7 +1080,7 @@ void CSQC_UpdateView(float w, float h) 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); } } diff --git a/qcsrc/client/announcer.qc b/qcsrc/client/announcer.qc index ce7077e436..7a4ed9223a 100644 --- a/qcsrc/client/announcer.qc +++ b/qcsrc/client/announcer.qc @@ -1,14 +1,6 @@ -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); @@ -16,32 +8,49 @@ void Announcer_Play(string announcement) 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) - centerprint_generic(CPID_GAME_STARTING, _("^1Begin!"), 1, 0); - - 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) - centerprint_generic(CPID_GAME_STARTING, _("^1Game starts in %d seconds"), 1, countdown_rounded); + 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)); } @@ -54,20 +63,28 @@ void Announcer_Countdown() * 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 } } @@ -106,7 +123,7 @@ void Announcer_Time() if not(autocvar_g_warmup_limit == -1 && warmup_stage) { announcer_5min = TRUE; - Announcer_Play("5minutesremain"); + Local_Notification(MSG_ANNCE, ANNCE_REMAINING_MIN_5); } } } @@ -128,7 +145,7 @@ void Announcer_Time() if not(autocvar_g_warmup_limit == -1 && warmup_stage) { announcer_1min = TRUE; - Announcer_Play("1minuteremains"); + Local_Notification(MSG_ANNCE, ANNCE_REMAINING_MIN_1); } } } @@ -139,50 +156,3 @@ void Announcer() 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")); -} diff --git a/qcsrc/client/autocvars.qh b/qcsrc/client/autocvars.qh index c7f7e9f279..c13e2bf6e8 100644 --- a/qcsrc/client/autocvars.qh +++ b/qcsrc/client/autocvars.qh @@ -78,6 +78,10 @@ string autocvar_cl_weaponpriority; float autocvar_cl_zoomfactor; float autocvar_cl_zoomsensitivity; float autocvar_cl_zoomspeed; +var float autocvar_cl_unpress_zoom_on_spawn = 1; +var float autocvar_cl_unpress_zoom_on_death = 1; +var float autocvar_cl_unpress_zoom_on_weapon_switch = 1; +var float autocvar_cl_unpress_attack_on_weapon_switch = 1; float autocvar_con_chat; float autocvar_con_chatpos; float autocvar_con_chatrect; @@ -249,12 +253,13 @@ float autocvar_hud_panel_healtharmor_text; 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_notify_fontsize; -float autocvar_hud_panel_notify_print; float autocvar_hud_panel_notify_time; float autocvar_hud_panel_physics; float autocvar_hud_panel_physics_acceleration_progressbar_mode; @@ -299,6 +304,7 @@ float autocvar_hud_panel_score; 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; diff --git a/qcsrc/client/csqcmodel_hooks.qc b/qcsrc/client/csqcmodel_hooks.qc index 1f8306e767..109b83d166 100644 --- a/qcsrc/client/csqcmodel_hooks.qc +++ b/qcsrc/client/csqcmodel_hooks.qc @@ -218,7 +218,7 @@ void CSQCPlayer_ForceModel_Apply(float islocalplayer) entity tm; for(tm = teams.sort_next; tm; tm = tm.sort_next) - if(tm.team != COLOR_SPECTATOR) + if(tm.team != NUM_SPECTATOR) ++teams_count; if(autocvar_cl_forcemyplayercolors) @@ -313,6 +313,10 @@ void CSQCPlayer_FallbackFrame_PostUpdate(float isnew) } 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) @@ -623,8 +627,8 @@ void CSQCModel_Hook_PreDraw(float isplayer) } else { - tracebox(self.origin + '0 0 1', self.mins, self.maxs, self.origin - '0 0 1', MOVE_NORMAL, self); - if(trace_fraction < 1 && trace_plane_normal_z > 0.7) + tracebox(self.origin + '0 0 1', self.mins, self.maxs, self.origin - '0 0 4', MOVE_NORMAL, self); + if(trace_startsolid || trace_fraction < 1) onground = 1; } animdecide_init(self); @@ -692,7 +696,9 @@ void CSQCModel_Hook_PostUpdate(float isnew, float isplayer, float islocalplayer) if(self.isplayermodel) { CSQCPlayer_ForceModel_PostUpdate(); - if(!isplayer) + if(isplayer) + CSQCPlayer_AnimDecide_PostUpdate(isnew); + else CSQCPlayer_FallbackFrame_PostUpdate(isnew); } CSQCModel_Effects_PostUpdate(); diff --git a/qcsrc/client/damage.qc b/qcsrc/client/damage.qc index cc89b03d79..bbc8f88043 100644 --- a/qcsrc/client/damage.qc +++ b/qcsrc/client/damage.qc @@ -211,43 +211,43 @@ void Ent_DamageInfo(float isNew) switch(w_deathtype) { - case DEATH_VHCRUSH: + case DEATH_VH_CRUSH: break; // spiderbot - case DEATH_SBMINIGUN: + case DEATH_VH_SPID_MINIGUN: string _snd; _snd = strcat("weapons/ric", ftos(1 + rint(random() * 2)), ".waw"); sound(self, CH_SHOTS, _snd, VOL_BASE, ATTN_NORM); pointparticles(particleeffectnum("spiderbot_minigun_impact"), self.origin, w_backoff * 1000, 1); break; - case DEATH_SBROCKET: + case DEATH_VH_SPID_ROCKET: sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM); pointparticles(particleeffectnum("spiderbot_rocket_explode"), self.origin, w_backoff * 1000, 1); break; - case DEATH_SBBLOWUP: + case DEATH_VH_SPID_DEATH: sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_MIN); pointparticles(particleeffectnum("explosion_big"), self.origin, w_backoff * 1000, 1); break; - case DEATH_WAKIGUN: + case DEATH_VH_WAKI_GUN: sound(self, CH_SHOTS, "weapons/laserimpact.wav", VOL_BASE, ATTN_NORM); pointparticles(particleeffectnum("wakizashi_gun_impact"), self.origin, w_backoff * 1000, 1); break; - case DEATH_WAKIROCKET: + case DEATH_VH_WAKI_ROCKET: sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM); pointparticles(particleeffectnum("wakizashi_rocket_explode"), self.origin, w_backoff * 1000, 1); break; - case DEATH_WAKIBLOWUP: + case DEATH_VH_WAKI_DEATH: sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_MIN); pointparticles(particleeffectnum("explosion_big"), self.origin, w_backoff * 1000, 1); break; - case DEATH_RAPTOR_CANNON: + case DEATH_VH_RAPT_CANNON: sound(self, CH_SHOTS, "weapons/laserimpact.wav", VOL_BASE, ATTN_NORM); pointparticles(particleeffectnum("raptor_cannon_impact"), self.origin, w_backoff * 1000, 1); break; - case DEATH_RAPTOR_BOMB_SPLIT: + case DEATH_VH_RAPT_FRAGMENT: float i; vector ang, vel; for(i = 1; i < 4; ++i) @@ -259,15 +259,15 @@ void Ent_DamageInfo(float isNew) sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM); pointparticles(particleeffectnum("raptor_bomb_spread"), self.origin, w_backoff * 1000, 1); break; - case DEATH_RAPTOR_BOMB: + case DEATH_VH_RAPT_BOMB: sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM); pointparticles(particleeffectnum("raptor_bomb_impact"), self.origin, w_backoff * 1000, 1); break; - case DEATH_RAPTOR_DEATH: + case DEATH_VH_RAPT_DEATH: sound(self, CH_SHOTS, "weapons/laserimpact.wav", VOL_BASE, ATTN_MIN); pointparticles(particleeffectnum("explosion_big"), self.origin, w_backoff * 1000, 1); break; - case DEATH_BUMB_GUN: + case DEATH_VH_BUMB_GUN: sound(self, CH_SHOTS, "weapons/fireball_impact2.wav", VOL_BASE, ATTN_NORM); pointparticles(particleeffectnum("bigplasma_impact"), self.origin, w_backoff * 1000, 1); break; @@ -301,14 +301,14 @@ void Ent_DamageInfo(float isNew) case DEATH_TURRET_MLRS: case DEATH_TURRET_HK: - case DEATH_TURRET_WALKER_ROCKET: + case DEATH_TURRET_WALK_ROCKET: case DEATH_TURRET_HELLION: sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_MIN); pointparticles(particleeffectnum("rocket_explode"), self.origin, w_backoff * 1000, 1); break; case DEATH_TURRET_MACHINEGUN: - case DEATH_TURRET_WALKER_GUN: + case DEATH_TURRET_WALK_GUN: _snd = strcat("weapons/ric", ftos(1 + rint(random() * 2)), ".waw"); sound(self, CH_SHOTS, _snd, VOL_BASE, ATTN_NORM); pointparticles(particleeffectnum("machinegun_impact"), self.origin, w_backoff * 1000, 1); @@ -319,7 +319,7 @@ void Ent_DamageInfo(float isNew) pointparticles(particleeffectnum("electro_impact"), self.origin, w_backoff * 1000, 1); break; - case DEATH_TURRET_WALKER_MEELE: + case DEATH_TURRET_WALK_MEELE: sound(self, CH_SHOTS, "weapons/ric1.wav", VOL_BASE, ATTN_MIN); pointparticles(particleeffectnum("TE_SPARK"), self.origin, w_backoff * 1000, 1); break; diff --git a/qcsrc/client/hook.qc b/qcsrc/client/hook.qc index 1c2894afa2..11070bae5c 100644 --- a/qcsrc/client/hook.qc +++ b/qcsrc/client/hook.qc @@ -129,22 +129,22 @@ void Draw_GrapplingHook() case ENT_CLIENT_HOOK: intensity = 1; offset = 0; - if(t == COLOR_TEAM1) + if(t == NUM_TEAM_1) { tex = "particles/hook_red"; rgb = '1 .3 .3'; } - else if(t == COLOR_TEAM2) + else if(t == NUM_TEAM_2) { tex = "particles/hook_blue"; rgb = '.3 .3 1'; } - else if(t == COLOR_TEAM3) + else if(t == NUM_TEAM_3) { tex = "particles/hook_yellow"; rgb = '1 1 .3'; } - else if(t == COLOR_TEAM4) + else if(t == NUM_TEAM_4) { tex = "particles/hook_pink"; rgb = '1 .3 1'; diff --git a/qcsrc/client/hud.qc b/qcsrc/client/hud.qc index afa6f23da9..469fe67fa2 100644 --- a/qcsrc/client/hud.qc +++ b/qcsrc/client/hud.qc @@ -154,18 +154,6 @@ void drawstringcenter(vector position, string text, vector scale, vector rgb, fl drawstring(position, text, scale, rgb, theAlpha, flag); } -// return the string of the given race place -string race_PlaceName(float pos) { - if(pos == 1) - return _("1st"); - else if(pos == 2) - return _("2nd"); - else if(pos == 3) - return _("3rd"); - else - return sprintf(_("%dth"), pos); -} - // return the string of the onscreen race timer string MakeRaceString(float cp, float mytime, float histime, float lapdelta, string hisname) { @@ -244,6 +232,30 @@ float race_CheckName(string net_name) { return 0; } +float GetPlayerColorForce(float i) +{ + if(!teamplay) + return 0; + else + return stof(getplayerkeyvalue(i, "colors")) & 15; +} + +float GetPlayerColor(float i) +{ + if not(playerslots[i].gotscores) // unconnected + return NUM_SPECTATOR; + else if(stof(getplayerkeyvalue(i, "frags")) == FRAGS_SPECTATOR) + return NUM_SPECTATOR; + else + return GetPlayerColorForce(i); +} + +string GetPlayerName(float i) +{ + return ColorTranslateRGB(getplayerkeyvalue(i, "name")); +} + + /* ================== HUD panels @@ -475,11 +487,9 @@ void HUD_Weapons(void) 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(); @@ -514,8 +524,7 @@ void HUD_Weapons(void) weaponorder_cmp_str = string_null; } - if(autocvar_hud_panel_weapons_complainbubble) - if(autocvar__hud_configure || time - complain_weapon_time >= when + fadetime) + if(!autocvar_hud_panel_weapons_complainbubble || autocvar__hud_configure || time - complain_weapon_time >= when + fadetime) complain_weapon = 0; // determine which weapons are going to be shown @@ -722,7 +731,7 @@ void HUD_Weapons(void) weapon_id = self.impulse; // skip if this weapon doesn't exist - if (!self || self.impulse < 0) { continue; } + if(!self || weapon_id < 0) { continue; } // skip this weapon if we don't own it (and onlyowned is enabled)-- or if weapons_complainbubble is showing for this weapon if(autocvar_hud_panel_weapons_onlyowned) @@ -939,10 +948,8 @@ void HUD_Ammo(void) 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(); @@ -1143,14 +1150,12 @@ void HUD_Powerups(void) } 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(); @@ -1386,14 +1391,12 @@ void HUD_HealthArmor(void) } 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; @@ -1617,564 +1620,36 @@ void HUD_HealthArmor(void) // Notification area (#4) // -string Weapon_SuicideMessage(float deathtype) +void HUD_Notify_Push(string icon, string attacker, string victim) { - w_deathtype = deathtype; - get_weaponinfo(DEATH_WEAPONOF(deathtype)).weapon_func(WR_SUICIDEMESSAGE); - return w_deathtypestring; -} - -string Weapon_KillMessage(float deathtype) -{ - w_deathtype = deathtype; - get_weaponinfo(DEATH_WEAPONOF(deathtype)).weapon_func(WR_KILLMESSAGE); - return w_deathtypestring; -} + if(icon != "") + { + --kn_index; + if (kn_index == -1) { kn_index = KN_MAX_ENTRIES-1; } + notify_times[kn_index] = time; -#define KN_MAX_ENTRIES 10 -float kn_index; -float killnotify_times[KN_MAX_ENTRIES]; -float killnotify_deathtype[KN_MAX_ENTRIES]; -float killnotify_actiontype[KN_MAX_ENTRIES]; // 0 = "Y [used by] X", 1 = "X [did action to] Y" -string killnotify_attackers[KN_MAX_ENTRIES]; -string killnotify_victims[KN_MAX_ENTRIES]; -void HUD_KillNotify_Push(string attacker, string victim, float actiontype, float wpn) -{ - --kn_index; - if (kn_index == -1) - kn_index = KN_MAX_ENTRIES-1; - killnotify_times[kn_index] = time; - killnotify_deathtype[kn_index] = wpn; - killnotify_actiontype[kn_index] = actiontype; - if(killnotify_attackers[kn_index]) - strunzone(killnotify_attackers[kn_index]); - killnotify_attackers[kn_index] = strzone(attacker); - if(killnotify_victims[kn_index]) - strunzone(killnotify_victims[kn_index]); - killnotify_victims[kn_index] = strzone(victim); -} + // icon + if(notify_icon[kn_index]) { strunzone(notify_icon[kn_index]); } + notify_icon[kn_index] = strzone(icon); -void HUD_KillNotify(string s1, string s2, string s3, float type, float msg) // s1 = attacker, s2 = victim -{ - float w; - float alsoprint, gentle; - alsoprint = (autocvar_hud_panel_notify_print || !panel_enabled); // print message to console if: notify panel disabled, or cvar to do so enabled - gentle = (autocvar_cl_gentle || autocvar_cl_gentle_messages); - - if ((msg == MSG_SUICIDE || msg == MSG_KILL || msg == MSG_KILL_ACTION) && gametype == MAPINFO_TYPE_CTS) // selfkill isn't interesting in CTS and only spams up the notify panel - return; + // attacker + if(notify_attackers[kn_index]) { strunzone(notify_attackers[kn_index]); } + notify_attackers[kn_index] = strzone(attacker); - if(msg == MSG_SUICIDE) { - w = DEATH_WEAPONOF(type); - if(WEP_VALID(w)) { - HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC); - if (alsoprint) - print("^1", sprintf(Weapon_SuicideMessage(type), strcat(s1, "^1")), "\n"); - } else if (type == DEATH_KILL) { - HUD_KillNotify_Push(s1, "", 0, DEATH_KILL); - if (alsoprint) - print (sprintf(_("^1%s^1 couldn't take it anymore\n"), s1)); - } else if (type == DEATH_ROT) { - HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC); - if (alsoprint) - print (sprintf(_("^1%s^1 died\n"), s1)); - } else if (type == DEATH_NOAMMO) { - HUD_KillNotify_Push(s1, "", 0, DEATH_NOAMMO); - if (alsoprint) - print (sprintf(_("^7%s^7 committed suicide. What's the point of living without ammo?\n"), s1)); - } else if (type == DEATH_CAMP) { - HUD_KillNotify_Push(s1, "", 0, DEATH_CAMP); - if (alsoprint) - print (sprintf(_("^1%s^1 thought they found a nice camping ground\n"), s1)); - } else if (type == KILL_TEAM_RED || type == KILL_TEAM_BLUE) { - HUD_KillNotify_Push(s1, "", 0, type); - if (alsoprint) - print (sprintf(_("^1%s^1 didn't become friends with the Lord of Teamplay\n"), s1)); - } else if (type == DEATH_CHEAT) { - HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC); - if (alsoprint) - print (sprintf(_("^1%s^1 unfairly eliminated themself\n"), s1)); - } else if (type == DEATH_FIRE) { - HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC); - if (alsoprint) - print (sprintf(_("^1%s^1 burned to death\n"), s1)); - } else if (type != DEATH_TEAMCHANGE && type != DEATH_QUIET) { - HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC); - if (alsoprint) - print (sprintf(_("^1%s^1 couldn't resist the urge to self-destruct\n"), s1)); - } - - if (stof(s2) > 2) // killcount > 2 - print (sprintf(_("^1%s^1 ended it all after a %d kill spree\n"), s1, stof(s2))); - } else if(msg == MSG_KILL) { - w = DEATH_WEAPONOF(type); - if(WEP_VALID(w)) { - HUD_KillNotify_Push(s1, s2, 1, type); - if (alsoprint) - print("^1", sprintf(Weapon_KillMessage(type), strcat(s2, "^1"), strcat(s1, "^1")), "\n"); // default order: victim, killer - } - else if(type == KILL_TEAM_RED || type == KILL_TEAM_BLUE || type == KILL_TEAM_SPREE) { - HUD_KillNotify_Push(s1, s2, 1, type); - if(alsoprint) - { - if(gentle) { - print (sprintf(_("^1%s^1 took action against a team mate\n"), s1)); - } else { - print (sprintf(_("^1%s^1 mows down a team mate\n"), s1)); - } - } - if (stof(s2) > 2 && type == KILL_TEAM_SPREE) { - if(gentle) - print (sprintf(_("^1%s^1 ended a %d scoring spree by going against a team mate\n"), s1, stof(s3))); - else - print (sprintf(_("^1%s^1 ended a %d kill spree by killing a team mate\n"), s1, stof(s3))); - } - else if (stof(s2) > 2) { - if(gentle) - print (sprintf(_("^1%s^1's %s scoring spree was ended by a team mate!\n"), s1, stof(s3))); - else - print (sprintf(_("^1%s^1's %s kill spree was ended by a team mate!\n"), s1, stof(s3))); - } - } - else if(type == KILL_FIRST_BLOOD) - print(sprintf(_("^1%s^1 drew first blood\n"), s1)); - else if (type == DEATH_TELEFRAG) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_TELEFRAG); - if(gentle) - print (sprintf(_("^1%s^1 tried to occupy %s^1's teleport destination space\n"), s2, s1)); - else - print (sprintf(_("^1%s^1 was telefragged by %s\n"), s2, s1)); - } - else if (type == DEATH_DROWN) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_DROWN); - if(alsoprint) - print (sprintf(_("^1%s^1 was drowned by %s\n"), s2, s1)); - } - else if (type == DEATH_SLIME) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_SLIME); - if(alsoprint) - print (sprintf(_("^1%s^1 was slimed by %s\n"), s2, s1)); - } - else if (type == DEATH_LAVA) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_LAVA); - if(alsoprint) - print (sprintf(_("^1%s^1 was cooked by %s\n"), s2, s1)); - } - else if (type == DEATH_FALL) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_FALL); - if(alsoprint) - print (sprintf(_("^1%s^1 was grounded by %s\n"), s2, s1)); - } - else if (type == DEATH_SHOOTING_STAR) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_SHOOTING_STAR); - if(alsoprint) - print (sprintf(_("^1%s^1 was shot into space by %s\n"), s2, s1)); - } - else if (type == DEATH_SWAMP) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 was conserved by %s\n"), s2, s1)); - } - else if (type == DEATH_HURTTRIGGER) - { - HUD_KillNotify_Push(s1, s2, 1, DEATH_HURTTRIGGER); - if(alsoprint) - print(sprintf(_("^1%s^1 was thrown into a world of hurt by %s\n"), s2, s1)); - } else if(type == DEATH_VHCRUSH) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 was crushed by %s\n"), s2, s1)); - } else if(type == DEATH_SBMINIGUN) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 got shredded by %s\n"), s2, s1)); - } else if(type == DEATH_SBROCKET) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 was blasted to bits by %s\n"), s2, s1)); - } else if(type == DEATH_SBBLOWUP) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 got caught in the blast when %s^1's destroys a vehicle\n"), s2, s1)); - } else if(type == DEATH_WAKIGUN) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 was bolted down by %s\n"), s2, s1)); - } else if(type == DEATH_BUMB_GUN) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 saw %s's preddy lights.\n"), s2, s1)); - } else if(type == DEATH_WAKIROCKET) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 could find no shelter from %s^1's rockets\n"), s2, s1)); - } else if(type == DEATH_WAKIBLOWUP) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 got caught in the blast when %s^1's destroys a vehicle\n"), s2, s1)); - } else if(type == DEATH_RAPTOR_CANNON) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 nailed to hell by %s\n"), s2, s1)); - } else if(type == DEATH_RAPTOR_BOMB) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 cluster crushed by %s\n"), s2, s1)); - } else if(type == DEATH_RAPTOR_DEATH) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 got caught in the blast when %s^1's destroys a vehicle\n"), s2, s1)); - } else if(type == DEATH_TURRET) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 was pushed into the line of fire by %s\n"), s2, s1)); - } else if(type == DEATH_TOUCHEXPLODE) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 was pushed into an accident by %s\n"), s2, s1)); - } else if(type == DEATH_CHEAT) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 was unfairly eliminated by %s\n"), s2, s1)); - } else if (type == DEATH_FIRE) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 was burnt to death by %s\n"), s2, s1)); - } else if (type == DEATH_CUSTOM) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_CUSTOM); - if(alsoprint) - print("^1", sprintf(s3, strcat(s2, "^1"), strcat(s1, "^1")), "\n"); - } else if (type == DEATH_HURTTRIGGER) { - HUD_KillNotify_Push(s1, s2, 1, DEATH_HURTTRIGGER); - if(alsoprint) - print("^1", sprintf(s3, strcat(s2, "^1"), strcat(s1, "^1")), "\n"); - } else { - HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 was fragged by %s\n"), s2, s1)); - } - } else if(msg == MSG_SPREE) { - if(type == KILL_END_SPREE) { - if(gentle) - print (sprintf(_("^1%s^1's %s scoring spree was ended by %s\n"), s1, s2, s3)); - else - print (sprintf(_("^1%s^1's %s kill spree was ended by %s\n"), s1, s2, s3)); - } else if(type == KILL_SPREE) { - if(gentle) - print (sprintf(_("^1%s^1 made %s scores in a row\n"), s1, s2)); - else - print (sprintf(_("^1%s^1 has %s frags in a row\n"), s1, s2)); - } else if(type == KILL_SPREE_3) { - if(gentle) - print (sprintf(_("%s^7 made a ^1TRIPLE SCORE\n"), s1)); - else - print (sprintf(_("%s^7 made a ^1TRIPLE FRAG\n"), s1)); - } else if(type == KILL_SPREE_5) { - if(gentle) - print (sprintf(_("%s^7 unleashes ^1SCORING RAGE\n"), s1)); - else - print (sprintf(_("%s^7 unleashes ^1RAGE\n"), s1)); - } else if(type == KILL_SPREE_10) { - if(gentle) - print (sprintf(_("%s^7 made ^1TEN SCORES IN A ROW!\n"), s1)); - else - print (sprintf(_("%s^7 starts the ^1MASSACRE!\n"), s1)); - } else if(type == KILL_SPREE_15) { - if(gentle) - print (sprintf(_("%s^7 made ^1FIFTEEN SCORES IN A ROW!\n"), s1)); - else - print (sprintf(_("%s^7 executes ^1MAYHEM!\n"), s1)); - } else if(type == KILL_SPREE_20) { - if(gentle) - print (sprintf(_("%s^7 made ^1TWENTY SCORES IN A ROW!\n"), s1)); - else - print (sprintf(_("%s^7 is a ^1BERSERKER!\n"), s1)); - } else if(type == KILL_SPREE_25) { - if(gentle) - print (sprintf(_("%s^7 made ^1TWENTY FIVE SCORES IN A ROW!\n"), s1)); - else - print (sprintf(_("%s^7 inflicts ^1CARNAGE!\n"), s1)); - } else if(type == KILL_SPREE_30) { - if(gentle) - print (sprintf(_("%s^7 made ^1THIRTY SCORES IN A ROW!\n"), s1)); - else - print (sprintf(_("%s^7 unleashes ^1ARMAGEDDON!\n"), s1)); - } - } else if(msg == MSG_KILL_ACTION) { // wtf is this? isnt it basically the same as MSG_SUICIDE? - if (type == DEATH_DROWN) { - HUD_KillNotify_Push(s1, "", 0, DEATH_DROWN); - if(alsoprint) - { - if(gentle) - print (sprintf(_("^1%s^1 was in the water for too long\n"), s1)); - else - print (sprintf(_("^1%s^1 drowned\n"), s1)); - } - } else if (type == DEATH_SLIME) { - HUD_KillNotify_Push(s1, "", 0, DEATH_SLIME); - if(alsoprint) - print (sprintf(_("^1%s^1 was slimed\n"), s1)); - } else if (type == DEATH_LAVA) { - HUD_KillNotify_Push(s1, "", 0, DEATH_LAVA); - if(alsoprint) - { - if(gentle) - print (sprintf(_("^1%s^1 found a hot place\n"), s1)); - else - print (sprintf(_("^1%s^1 turned into hot slag\n"), s1)); - } - } else if (type == DEATH_FALL) { - HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC); - if(alsoprint) - { - if(gentle) - print (sprintf(_("^1%s^1 tested gravity (and it worked)\n"), s1)); - else - print (sprintf(_("^1%s^1 hit the ground with a crunch\n"), s1)); - } - } else if (type == DEATH_SHOOTING_STAR) { - HUD_KillNotify_Push(s1, "", 0, DEATH_SHOOTING_STAR); - if(alsoprint) - print (sprintf(_("^1%s^1 became a shooting star\n"), s1)); - } else if (type == DEATH_SWAMP) { - HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC); - if(alsoprint) - { - if(gentle) - print (sprintf(_("^1%s^1 discovered a swamp\n"), s1)); - else - print (sprintf(_("^1%s^1 is now conserved for centuries to come\n"), s1)); - } - } else if(DEATH_ISTURRET(type)) { - HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC); - if(alsoprint) - { - if(gentle) - print (sprintf(_("^1%s^1 ran into a turret\n"), s1)); - else - { - switch(type) - { - case DEATH_TURRET_EWHEEL: - print (sprintf(_("^1%s^1 was laserd down by a eWheel turret \n"), s1)); - break; - case DEATH_TURRET_FLAC: - print (sprintf(_("^1%s^1 got caught in the flac \n"), s1)); - break; - case DEATH_TURRET_MACHINEGUN: - print (sprintf(_("^1%s^1 was riddeld full of riddled by a machinegun turret \n"), s1)); - break; - case DEATH_TURRET_WALKER_GUN: - print (sprintf(_("^1%s^1 got served a led enrichment by a walker turret \n"), s1)); - break; - case DEATH_TURRET_WALKER_MEELE: - print (sprintf(_("^1%s^1 was impaled by a walker turret \n"), s1)); - break; - case DEATH_TURRET_WALKER_ROCKET: - print (sprintf(_("^1%s^1 was rocketed to hell by a walker turret \n"), s1)); - break; - case DEATH_TURRET_HELLION: - print (sprintf(_("^1%s^1 was blasted away hellion turret \n"), s1)); - break; - case DEATH_TURRET_HK: - print (sprintf(_("^1%s^1 could not hide from the hunter turret \n"), s1)); - break; - case DEATH_TURRET_MLRS: - print (sprintf(_("^1%s^1 got turned into smoldering gibs by a mlrs turret \n"), s1)); - break; - case DEATH_TURRET_PLASMA: - print (sprintf(_("^1%s^1 got served some superheated plasma from a plasma turret \n"), s1)); - break; - case DEATH_TURRET_PHASER: - print (sprintf(_("^1%s^1 was phased out \n"), s1)); - break; - case DEATH_TURRET_TESLA: - print (sprintf(_("^1%s^1 was electrocuted by a tesla turret \n"), s1)); - break; - } - } - } - } else if (type == DEATH_CUSTOM) { - HUD_KillNotify_Push(s1, "", 0, DEATH_CUSTOM); - if(alsoprint) - print("^1", sprintf(s2, strcat(s1, "^1")), "\n"); - } else if (type == DEATH_HURTTRIGGER) { - HUD_KillNotify_Push(s1, "", 0, DEATH_HURTTRIGGER); - if(alsoprint) - print("^1", sprintf(s2, strcat(s1, "^1")), "\n"); - } else if(type == DEATH_TOUCHEXPLODE) { - HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 died in an accident\n"), s1)); - } else if(type == DEATH_CHEAT) { - HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC); - if(alsoprint) - print (sprintf(_("^1%s^1 was unfairly eliminated\n"), s1)); - } else if(type == DEATH_FIRE) { - HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC); - if(alsoprint) - { - if(gentle) - print (sprintf(_("^1%s^1 felt a little hot\n"), s1)); - else - print (sprintf(_("^1%s^1 burnt to death\n"), s1)); - } - } else { - HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC); - if(alsoprint) - { - if(gentle) - print (sprintf(_("^1%s^1 needs a restart\n"), s1)); - else - print (sprintf(_("^1%s^1 died\n"), s1)); - } - } - } else if(msg == MSG_KILL_ACTION_SPREE) { - if(gentle) - print (sprintf(_("^1%s^1 needs a restart after a %d scoring spree\n"), s1, stof(s2))); - else - print (sprintf(_("^1%s^1 died with a %d kill spree\n"), s1, stof(s2))); - } else if(msg == MSG_INFO) { - if(type == INFO_GOTFLAG) { // here, s2 is the flag name - HUD_KillNotify_Push(s1, s2, 0, INFO_GOTFLAG); - print(sprintf(_("%s^7 got the %s\n"), s1, s2)); - } else if(type == INFO_LOSTFLAG) { - HUD_KillNotify_Push(s1, s2, 0, INFO_LOSTFLAG); - print(sprintf(_("%s^7 lost the %s\n"), s1, s2)); - } else if(type == INFO_PICKUPFLAG) { - HUD_KillNotify_Push(s1, s2, 0, INFO_GOTFLAG); - print(sprintf(_("%s^7 picked up the %s\n"), s1, s2)); - } else if(type == INFO_RETURNFLAG) { - HUD_KillNotify_Push(s1, s2, 0, INFO_RETURNFLAG); - print(sprintf(_("%s^7 returned the %s\n"), s1, s2)); - } else if(type == INFO_CAPTUREFLAG) { - HUD_KillNotify_Push(s1, s2, 0, INFO_CAPTUREFLAG); - print(sprintf(_("%s^7 captured the %s%s\n"), s1, s2, s3)); - } - } else if(msg == MSG_RACE) { - if(type == RACE_SERVER_RECORD) { - HUD_KillNotify_Push(s1, s2, 1, RACE_SERVER_RECORD); - } - else if(type == RACE_NEW_RANK) { - HUD_KillNotify_Push(s1, s2, 1, RACE_NEW_RANK); - } - else if(type == RACE_NEW_TIME) { - HUD_KillNotify_Push(s1, s2, 1, RACE_NEW_TIME); - } - else if(type == RACE_FAIL) { - HUD_KillNotify_Push(s1, s2, 1, RACE_FAIL); - } - } else if(msg == MSG_KA) { - if(type == KA_PICKUPBALL) { - HUD_KillNotify_Push(s1, s2, 0, KA_PICKUPBALL); - if(alsoprint) - print (sprintf(_("%s^7 has picked up the ball!\n"), s1)); - } - else if(type == KA_DROPBALL) { - HUD_KillNotify_Push(s1, s2, 0, KA_DROPBALL); - if(alsoprint) - print(sprintf(_("%s^7 has dropped the ball!\n"), s1)); - } - } -} - -void HUD_KillCenterprint(string s1, string s2, float type, float msg) -{ - float gentle; - gentle = (autocvar_cl_gentle || autocvar_cl_gentle_messages); - if(msg == MSG_SUICIDE) { - if (type == DEATH_TEAMCHANGE) { - centerprint_hud(sprintf(_("You are now on: %s"), s1)); - } else if (type == DEATH_AUTOTEAMCHANGE) { - centerprint_hud(sprintf(_("You have been moved into a different team to improve team balance\nYou are now on: %s"), s1)); - } else if (type == DEATH_CAMP) { - if(gentle) - centerprint_hud(_("^1Reconsider your tactics, camper!")); - else - centerprint_hud(_("^1Die camper!")); - } else if (type == DEATH_NOAMMO) { - if(gentle) - centerprint_hud(_("^1You are reinserted into the game for running out of ammo...")); - else - centerprint_hud(_("^1You were killed for running out of ammo...")); - } else if (type == DEATH_ROT) { - if(gentle) - centerprint_hud(_("^1You need to preserve your health")); - else - centerprint_hud(_("^1You grew too old without taking your medicine")); - } else if (type == KILL_TEAM_RED || type == KILL_TEAM_BLUE) { - if(gentle) - centerprint_hud(_("^1Don't go against team mates!")); - else - centerprint_hud(_("^1Don't shoot your team mates!")); - } else if (type == DEATH_QUIET) { - // do nothing - } else { // generic message - if(gentle) - centerprint_hud(_("^1You need to be more careful!")); - else - centerprint_hud(_("^1You killed your own dumb self!")); - } - } else if(msg == MSG_KILL) { - if (type == KILL_TEAM_RED || type == KILL_TEAM_BLUE) { - if(gentle) { - centerprint_hud(sprintf(_("^1Moron! You went against ^7%s^1, a team mate!"), s1)); - } else { - centerprint_hud(sprintf(_("^1Moron! You fragged ^7%s^1, a team mate!"), s1)); - } - } else if (type == KILL_FIRST_BLOOD) { - if(gentle) { - centerprint_hud(_("^1First score")); - } else { - centerprint_hud(_("^1First blood")); - } - } else if (type == KILL_FIRST_VICTIM) { - if(gentle) { - centerprint_hud(_("^1First casualty")); - } else { - centerprint_hud(_("^1First victim")); - } - } else if (type == KILL_TYPEFRAG) { // s2 contains "advanced kill messages" such as ping, handicap... - if(gentle) { - centerprint_hud(strcat(sprintf(_("^1You scored against ^7%s^1 who was typing!"), s1), s2)); - } else { - centerprint_hud(strcat(sprintf(_("^1You typefragged ^7%s"), s1), s2)); - } - } else if (type == KILL_TYPEFRAGGED) { - if(gentle) { - centerprint_hud(strcat(sprintf(_("^1You were scored against by ^7%s^1 while you were typing!"), s1), s2)); - } else { - centerprint_hud(strcat(sprintf(_("^1You were typefragged by ^7%s"), s1), s2)); - } - } else if (type == KILL_FRAG) { - if(gentle) { - centerprint_hud(strcat(sprintf(_("^4You scored against ^7%s"), s1), s2)); - } else { - centerprint_hud(strcat(sprintf(_("^4You fragged ^7%s"), s1), s2)); - } - } else { // generic message - if(gentle) { - centerprint_hud(strcat(sprintf(_("^1You were scored against by ^7%s"), s1), s2)); - } else { - centerprint_hud(strcat(sprintf(_("^1You were fragged by ^7%s"), s1), s2)); - } - } - } else if(msg == MSG_KILL_ACTION) { - // TODO: invent more centerprints here? - centerprint_hud(_("^1Watch your step!")); + // victim + if(notify_victims[kn_index]) { strunzone(notify_victims[kn_index]); } + notify_victims[kn_index] = strzone(victim); } } -void HUD_Notify (void) +void HUD_Notify(void) { if(!autocvar__hud_configure) { 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; @@ -2201,14 +1676,11 @@ void HUD_Notify (void) float fadetime; fadetime = autocvar_hud_panel_notify_fadetime; - string s; - - vector pos_attacker, pos_victim; - vector weap_pos; + vector pos_attacker, pos_victim, pos_icon; float width_attacker; - string attacker, victim; + string attacker, victim, icon; - float i, j, w, type, step, limit; + float i, j, step, limit; if(autocvar_hud_panel_notify_flip) //order items from the top down { i = 0; @@ -2232,230 +1704,62 @@ void HUD_Notify (void) a = entries - 1 - i; attacker = textShortenToWidth(sprintf(_("Player %d"), a+1), 0.48 * mySize_x - height, fontsize, stringwidth_colors); victim = textShortenToWidth(sprintf(_("Player %d"), a+2), 0.48 * mySize_x - height, fontsize, stringwidth_colors); - s = strcat("weapon", get_weaponinfo(WEP_FIRST + mod(floor(a*2.4), WEP_LAST)).netname); + icon = strcat("weapon", get_weaponinfo(WEP_FIRST + mod(floor(a*2.4), WEP_LAST)).netname); a = bound(0, (when - a) / 4, 1); goto hud_config_notifyprint; } - - if (j == KN_MAX_ENTRIES) - j = 0; - - if(killnotify_times[j] + when > time) - a = 1; - else if(fadetime) - { - a = bound(0, (killnotify_times[j] + when + fadetime - time) / fadetime, 1); - if(!a) - { - break; - } - } else { - break; - } - - s = ""; - - type = killnotify_deathtype[j]; - w = DEATH_WEAPONOF(type); + if (j == KN_MAX_ENTRIES) + j = 0; - // TODO: maybe print in team colors? - // - // Y [used by] X - if(killnotify_actiontype[j] == 0) - { - if(type == DEATH_GENERIC) - { - s = "notify_death"; - } - else if(type == DEATH_NOAMMO) - { - s = "notify_outofammo"; - } - else if(type == DEATH_KILL) - { - s = "notify_selfkill"; - } - else if(type == DEATH_CAMP) - { - s = "notify_camping"; - } - else if(type == KILL_TEAM_RED) - { - s = "notify_teamkill_red"; - } - else if(type == KILL_TEAM_BLUE) - { - s = "notify_teamkill_blue"; - } - else if(type == DEATH_DROWN) - { - s = "notify_water"; - } - else if(type == DEATH_SLIME) - { - s = "notify_slime"; - } - else if(type == DEATH_LAVA) - { - s = "notify_lava"; - } - else if(type == DEATH_FALL) - { - s = "notify_fall"; - } - else if(type == DEATH_SHOOTING_STAR) - { - s = "notify_shootingstar"; - } - else if(type == DEATH_HURTTRIGGER || type == DEATH_CUSTOM) - { - s = "notify_death"; - } - else if(type == INFO_GOTFLAG) - { - if(killnotify_victims[j] == "^1RED^7 flag") - { - s = "notify_red_taken"; - } - else - { - s = "notify_blue_taken"; - } - } - else if(type == INFO_RETURNFLAG) - { - if(killnotify_victims[j] == "^1RED^7 flag") - { - s = "notify_red_returned"; - } - else - { - s = "notify_blue_returned"; - } - } - else if(type == INFO_LOSTFLAG) - { - if(killnotify_victims[j] == "^1RED^7 flag") - { - s = "notify_red_lost"; - } - else - { - s = "notify_blue_lost"; - } - } - else if(type == INFO_CAPTUREFLAG) + if(notify_times[j] + when > time) + a = 1; + else if(fadetime) { - if(killnotify_victims[j] == "^1RED^7 flag") + a = bound(0, (notify_times[j] + when + fadetime - time) / fadetime, 1); + if(!a) { - s = "notify_red_captured"; - } - else - { - s = "notify_blue_captured"; + break; } } - else if(type == KA_DROPBALL) - { - s = "notify_balldropped"; - } - else if(type == KA_PICKUPBALL) + else { - s = "notify_ballpickedup"; + break; } - attacker = textShortenToWidth(killnotify_attackers[j], 0.48 * mySize_x - height, fontsize, stringwidth_colors); - pos_attacker = pos + eX * (0.52 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight))); - weap_pos = pos + eX * 0.5 * mySize_x - eX * height + eY * i * height; - - if(s != "") - { - drawpic_aspect_skin(weap_pos, s, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); - drawcolorcodedstring(pos_attacker, attacker, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL); - } + attacker = notify_attackers[j]; + victim = notify_victims[j]; + icon = notify_icon[j]; } - // X [did action to] Y - else + + //type = notify_deathtype[j]; + //w = DEATH_WEAPONOF(type); + + if(icon != "") { - if(type & HITTYPE_SECONDARY && w == WEP_LASER) - { - s = "notify_melee_laser"; - } - else if(type & HITTYPE_SECONDARY && w == WEP_SHOTGUN) - { - s = "notify_melee_shotgun"; - } - else if(WEP_VALID(w)) - { - self = get_weaponinfo(w); - s = strcat("weapon", self.netname); - } - else if(type == KILL_TEAM_RED) - { - s = "notify_teamkill_red"; - } - else if(type == KILL_TEAM_BLUE) + if((attacker != "") && (victim == "")) { - s = "notify_teamkill_red"; - } - else if(type == DEATH_TELEFRAG) - { - s = "notify_telefrag"; - } - else if(type == DEATH_DROWN) - { - s = "notify_water"; - } - else if(type == DEATH_SLIME) - { - s = "notify_slime"; - } - else if(type == DEATH_LAVA) - { - s = "notify_lava"; - } - else if(type == DEATH_FALL) - { - s = "notify_fall"; - } - else if(type == DEATH_SHOOTING_STAR) - { - s = "notify_shootingstar"; - } - else if(type == DEATH_HURTTRIGGER || type == DEATH_CUSTOM) // DEATH_CUSTOM is also void, right? - { - s = "notify_void"; - } - else if(type == RACE_SERVER_RECORD) - { - s = "race_newrecordserver"; - } - else if(type == RACE_NEW_RANK) - { - s = "race_newrankyellow"; - } - else if(type == RACE_NEW_TIME) - { - s = "race_newtime"; + // Y [used by] X + attacker = textShortenToWidth(attacker, 0.73 * mySize_x - height, fontsize, stringwidth_colors); + pos_attacker = pos + eX * (0.27 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight))); + pos_icon = pos + eX * 0.25 * mySize_x - eX * height + eY * i * height; + + drawpic_aspect_skin(pos_icon, icon, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); + drawcolorcodedstring(pos_attacker, attacker, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL); } - else if(type == RACE_FAIL) + else if((attacker != "") && (victim != "")) { - s = "race_newfail"; - } - - attacker = textShortenToWidth(killnotify_attackers[j], 0.48 * mySize_x - height, fontsize, stringwidth_colors); - victim = textShortenToWidth(killnotify_victims[j], 0.48 * mySize_x - height, fontsize, stringwidth_colors); + // X [did action to] Y + attacker = textShortenToWidth(attacker, 0.48 * mySize_x - height, fontsize, stringwidth_colors); + victim = textShortenToWidth(victim, 0.48 * mySize_x - height, fontsize, stringwidth_colors); :hud_config_notifyprint - width_attacker = stringwidth(attacker, TRUE, fontsize); - pos_attacker = pos + eX * (0.48 * mySize_x - height - width_attacker) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight))); - pos_victim = pos + eX * (0.52 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight))); - weap_pos = pos + eX * 0.5 * mySize_x - eX * height + eY * i * height; + width_attacker = stringwidth(attacker, TRUE, fontsize); + pos_attacker = pos + eX * (0.48 * mySize_x - height - width_attacker) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight))); + pos_victim = pos + eX * (0.52 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight))); + pos_icon = pos + eX * 0.5 * mySize_x - eX * height + eY * i * height; - if(s != "") - { - drawpic_aspect_skin(weap_pos, s, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); + drawpic_aspect_skin(pos_icon, icon, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL); drawcolorcodedstring(pos_attacker, attacker, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL); drawcolorcodedstring(pos_victim, victim, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL); } @@ -2481,10 +1785,8 @@ void HUD_Timer(void) { 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(); @@ -2551,12 +1853,10 @@ void HUD_Radar(void) 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) @@ -2706,13 +2006,13 @@ void HUD_Radar(void) for(tm = world; (tm = find(tm, classname, "entcs_receiver")); ) { color2 = GetPlayerColor(tm.sv_entnum); - //if(color == COLOR_SPECTATOR || color == color2) - draw_teamradar_player(tm.origin, tm.angles, GetTeamRGB(color2)); + //if(color == NUM_SPECTATOR || color == color2) + draw_teamradar_player(tm.origin, tm.angles, Team_ColorRGB(color2)); } draw_teamradar_player(view_origin, view_angles, '1 1 1'); drawresetcliparea(); -}; +} // Score (#7) // @@ -2746,7 +2046,7 @@ void HUD_Score_Rankings(vector pos, vector mySize, entity me, float team_count) for(i=0; i= rows) { @@ -3020,11 +2318,11 @@ void HUD_Score(void) else if(tm.team == myteam) { if (max_fragcount == score) HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); - drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize_x + eY * mySize_y, GetTeamRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize_x + eY * mySize_y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL); } else { if (max_fragcount == score) HUD_Panel_DrawHighlight(pos + eX * 0.75 * mySize_x + eY * (1/3) * rows * mySize_y, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); - drawstring_aspect(pos + eX * 0.75 * mySize_x + eY * (1/3) * rows * mySize_y, ftos(score), score_size, GetTeamRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring_aspect(pos + eX * 0.75 * mySize_x + eY * (1/3) * rows * mySize_y, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL); ++rows; } } @@ -3042,10 +2340,8 @@ void HUD_RaceTimer (void) 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(); @@ -3194,7 +2490,7 @@ float vote_prev; // previous state of vote_active to check for a change 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))) { @@ -3226,8 +2522,6 @@ void HUD_VoteWindow(void) } else { - hud_configure_active_panel = HUD_PANEL_VOTE; - vote_yescount = 3; vote_nocount = 2; vote_needed = 4; @@ -3248,7 +2542,7 @@ void HUD_VoteWindow(void) if(!vote_alpha) return; - HUD_Panel_UpdateCvars(vote); + HUD_Panel_UpdateCvars(); HUD_Panel_ApplyFadeAlpha(); if(uid2name_dialog) @@ -3339,32 +2633,100 @@ void HUD_VoteWindow(void) 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= rows) + { + row = 0; + ++column; + } } } @@ -3438,7 +2800,7 @@ void HUD_Mod_CTF(vector pos, vector mySize) case 2: red_icon = "flag_red_lost"; break; case 3: red_icon = "flag_red_carrying"; red_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; default: - if((stat_items & IT_CTF_SHIELDED) && (myteam == COLOR_TEAM2)) + if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_2)) red_icon = "flag_red_shielded"; else red_icon = string_null; @@ -3451,7 +2813,7 @@ void HUD_Mod_CTF(vector pos, vector mySize) default: if(redflag == 3) red_icon_prevstatus = "flag_red_carrying"; // make it more visible - else if((stat_items & IT_CTF_SHIELDED) && (myteam == COLOR_TEAM2)) + else if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_2)) red_icon_prevstatus = "flag_red_shielded"; else red_icon_prevstatus = string_null; @@ -3466,7 +2828,7 @@ void HUD_Mod_CTF(vector pos, vector mySize) case 2: blue_icon = "flag_blue_lost"; break; case 3: blue_icon = "flag_blue_carrying"; blue_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; default: - if((stat_items & IT_CTF_SHIELDED) && (myteam == COLOR_TEAM1)) + if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_1)) blue_icon = "flag_blue_shielded"; else blue_icon = string_null; @@ -3479,7 +2841,7 @@ void HUD_Mod_CTF(vector pos, vector mySize) default: if(blueflag == 3) blue_icon_prevstatus = "flag_blue_carrying"; // make it more visible - else if((stat_items & IT_CTF_SHIELDED) && (myteam == COLOR_TEAM1)) + else if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_1)) blue_icon_prevstatus = "flag_blue_shielded"; else blue_icon_prevstatus = string_null; @@ -3487,7 +2849,7 @@ void HUD_Mod_CTF(vector pos, vector mySize) } if(mySize_x > mySize_y) { - if (myteam == COLOR_TEAM1) { // always draw own flag on left + if (myteam == NUM_TEAM_1) { // always draw own flag on left redflag_pos = pos; blueflag_pos = pos + eX * 0.5 * mySize_x; } else { @@ -3496,7 +2858,7 @@ void HUD_Mod_CTF(vector pos, vector mySize) } flag_size = eX * 0.5 * mySize_x + eY * mySize_y; } else { - if (myteam == COLOR_TEAM1) { // always draw own flag on left + if (myteam == NUM_TEAM_1) { // always draw own flag on left redflag_pos = pos; blueflag_pos = pos + eY * 0.5 * mySize_y; } else { @@ -3610,16 +2972,16 @@ void HUD_Mod_KH(vector pos, vector mySize) { switch(keyteam) { - case COLOR_TEAM1: + case NUM_TEAM_1: drawpic_aspect_skin(pa, "kh_redarrow", kh_asize, '1 1 1', aa, DRAWFLAG_NORMAL); // show 30% theAlpha key break; - case COLOR_TEAM2: + case NUM_TEAM_2: drawpic_aspect_skin(pa, "kh_bluearrow", kh_asize, '1 1 1', aa, DRAWFLAG_NORMAL); // show 30% theAlpha key break; - case COLOR_TEAM3: + case NUM_TEAM_3: drawpic_aspect_skin(pa, "kh_yellowarrow", kh_asize, '1 1 1', aa, DRAWFLAG_NORMAL); // show 30% theAlpha key break; - case COLOR_TEAM4: + case NUM_TEAM_4: drawpic_aspect_skin(pa, "kh_pinkarrow", kh_asize, '1 1 1', aa, DRAWFLAG_NORMAL); // show 30% theAlpha key break; default: @@ -3853,7 +3215,7 @@ void HUD_Mod_Race(vector pos, vector mySize) else rank = 0; string rankname; - rankname = race_PlaceName(rank); + rankname = count_ordinal(rank); vector namepos; namepos = medalPos + '0 0.8 0' * squareSize; @@ -3966,7 +3328,7 @@ void HUD_Mod_Dom(vector myPos, vector mySize) entity tm; float teams_count = 0; for(tm = teams.sort_next; tm; tm = tm.sort_next) - if(tm.team != COLOR_SPECTATOR) + if(tm.team != NUM_SPECTATOR) ++teams_count; float layout = autocvar_hud_panel_modicons_dom_layout; @@ -3978,11 +3340,11 @@ void HUD_Mod_Dom(vector myPos, vector mySize) 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 hud_configure_cp_generation_time) @@ -4867,7 +4218,7 @@ void HUD_CenterPrint (void) } } - HUD_Panel_UpdateCvars(centerprint); + HUD_Panel_UpdateCvars(); // this panel doesn't fade when showing the scoreboard if(autocvar__menu_alpha) @@ -4909,7 +4260,7 @@ void HUD_CenterPrint (void) fontsize = '1 1 0' * height; entries = bound(1, floor(panel_size_y/height), CENTERPRINT_MAX_ENTRIES); - float i, j, k, n; + float i, j, k, n, g; float a, sz, align, current_msg_pos_y = 0, msg_size; vector pos; string ts; @@ -4920,7 +4271,7 @@ void HUD_CenterPrint (void) if (autocvar_hud_panel_centerprint_flip) pos_y += panel_size_y; align = bound(0, autocvar_hud_panel_centerprint_align, 1); - for (i=0, j=cpm_index; i time) + if(centerprint_time[j] < 0) + a = bound(0, (time - centerprint_expire_time[j]) / max(0.0001, autocvar_hud_panel_centerprint_fade_in), 1); + else if(centerprint_expire_time[j] - autocvar_hud_panel_centerprint_fade_out > time) a = bound(0, (time - (centerprint_expire_time[j] - centerprint_time[j])) / max(0.0001, autocvar_hud_panel_centerprint_fade_in), 1); - else if (centerprint_expire_time[j] > time) + else if(centerprint_expire_time[j] > time) a = (centerprint_expire_time[j] - time) / max(0.0001, autocvar_hud_panel_centerprint_fade_out); else a = 0; @@ -4951,8 +4305,8 @@ void HUD_CenterPrint (void) // also fade it based on positioning if(autocvar_hud_panel_centerprint_fade_subsequent) { - a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passone_minalpha, (1 - (i / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passone))), 1); // pass one: all messages after the first have half theAlpha - a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passtwo_minalpha, (1 - (i / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passtwo))), 1); // pass two: after that, gradually lower theAlpha even more for each message + a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passone_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passone))), 1); // pass one: all messages after the first have half theAlpha + a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passtwo_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passtwo))), 1); // pass two: after that, gradually lower theAlpha even more for each message } // finally set the size based on the new theAlpha from subsequent fading @@ -4960,7 +4314,7 @@ void HUD_CenterPrint (void) drawfontscale = sz * '1 1 0'; if (centerprint_countdown_num[j]) - n = tokenizebyseparator(sprintf(centerprint_messages[j], centerprint_countdown_num[j]), "\n"); + n = tokenizebyseparator(strreplace("^COUNT", count_seconds(centerprint_countdown_num[j]), centerprint_messages[j]), "\n"); else n = tokenizebyseparator(centerprint_messages[j], "\n"); @@ -5000,6 +4354,9 @@ void HUD_CenterPrint (void) pos_y += fontsize_y * CENTERPRINT_SPACING/2; } } + + ++g; // move next position number up + msg_size = pos_y - msg_size; if (autocvar_hud_panel_centerprint_flip) { @@ -5049,44 +4406,6 @@ void HUD_Reset (void) 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; @@ -5116,7 +4435,7 @@ void HUD_Main (void) // 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; } @@ -5165,8 +4484,10 @@ void HUD_Main (void) vector color; float hud_dock_color_team = autocvar_hud_dock_color_team; if((teamplay) && hud_dock_color_team) { - f = stof(getplayerkeyvalue(current_player - 1, "colors")); - color = colormapPaletteColor(mod(f, 16), 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; @@ -5241,31 +4562,35 @@ void HUD_Main (void) 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) diff --git a/qcsrc/client/hud.qh b/qcsrc/client/hud.qh index 0da6ac5d08..19cd36ddb0 100644 --- a/qcsrc/client/hud.qh +++ b/qcsrc/client/hud.qh @@ -1,4 +1,10 @@ -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; @@ -8,7 +14,7 @@ vector mousepos; 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; @@ -48,17 +54,29 @@ float hud_fade_alpha; 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; @@ -76,8 +94,52 @@ var string panel_bg_border_str; 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 @@ -126,7 +188,10 @@ if(!autocvar__hud_configure && panel_bg_str == "0") {\ // 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(mod(stof(getplayerkeyvalue(current_player - 1, "colors")), 16), 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 {\ @@ -153,7 +218,7 @@ if(panel_bg_color_team_str == "") {\ // 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;\ @@ -169,7 +234,7 @@ panel_bg_alpha = stof(panel_bg_alpha_str);\ 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);\ @@ -256,87 +321,66 @@ else\ }\ } -// 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 + +float kn_index; +float notify_times[KN_MAX_ENTRIES]; +string notify_icon[KN_MAX_ENTRIES]; +string notify_attackers[KN_MAX_ENTRIES]; +string notify_victims[KN_MAX_ENTRIES]; +void HUD_Notify_Push(string icon, string attacker, string victim); diff --git a/qcsrc/client/hud_config.qc b/qcsrc/client/hud_config.qc index ea9fd93fac..ca8ec19c1a 100644 --- a/qcsrc/client/hud_config.qc +++ b/qcsrc/client/hud_config.qc @@ -2,8 +2,8 @@ // 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) { @@ -52,7 +52,7 @@ 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"); @@ -117,7 +117,6 @@ void HUD_Panel_ExportCfg(string cfgname) case HUD_PANEL_NOTIFY: HUD_Write_PanelCvar_q("_flip"); HUD_Write_PanelCvar_q("_fontsize"); - HUD_Write_PanelCvar_q("_print"); HUD_Write_PanelCvar_q("_time"); HUD_Write_PanelCvar_q("_fadetime"); break; @@ -141,7 +140,9 @@ void HUD_Panel_ExportCfg(string cfgname) 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"); @@ -218,10 +219,10 @@ vector HUD_Panel_CheckMove(vector myPos, vector mySize) 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; @@ -281,7 +282,8 @@ vector HUD_Panel_CheckMove(vector myPos, vector mySize) void HUD_Panel_SetPos(vector pos) { - HUD_Panel_UpdatePosSizeForId(highlightedPanel); + panel = highlightedPanel; + HUD_Panel_UpdatePosSize() vector mySize; mySize = panel_size; @@ -303,8 +305,7 @@ void HUD_Panel_SetPos(vector pos) 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 @@ -318,10 +319,10 @@ vector HUD_Panel_CheckResize(vector mySize, vector resizeorigin) { 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; @@ -420,7 +421,8 @@ vector HUD_Panel_CheckResize(vector mySize, vector resizeorigin) { 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 @@ -429,7 +431,7 @@ void HUD_Panel_SetPosSize(vector mySize) 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); @@ -500,20 +502,19 @@ void HUD_Panel_SetPosSize(vector mySize) //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); @@ -548,7 +549,8 @@ void HUD_Panel_Arrow_Action(float nPrimary) 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; @@ -607,7 +609,8 @@ void HUD_Panel_Arrow_Action(float nPrimary) HUD_Panel_SetPos(pos); } - HUD_Panel_UpdatePosSizeForId(highlightedPanel); + panel = highlightedPanel; + HUD_Panel_UpdatePosSize() if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size) { @@ -627,15 +630,16 @@ float prevMouseClickedTime; // time during previous left mouse click, to check f 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) { @@ -686,14 +690,14 @@ 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(); } } @@ -737,15 +741,18 @@ float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary) //(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 @@ -764,35 +771,36 @@ float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary) 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) @@ -809,18 +817,15 @@ float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary) } } - 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" : ""); } @@ -829,11 +834,11 @@ float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary) 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 @@ -841,10 +846,11 @@ float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary) 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; @@ -862,22 +868,20 @@ float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary) 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) @@ -897,7 +901,7 @@ float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary) { if (bInputType == 1) return true; - if (highlightedPanel != -1) + if (highlightedPanel) HUD_Panel_EnableMenu(); } else if(hit_con_bind) @@ -915,7 +919,8 @@ float HUD_Panel_Check_Mouse_Pos(float allow_move) 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 @@ -995,14 +1000,15 @@ void HUD_Panel_Highlight(float allow_move) 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; @@ -1011,7 +1017,7 @@ void HUD_Panel_Highlight(float allow_move) // 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; @@ -1022,7 +1028,7 @@ void HUD_Panel_Highlight(float allow_move) // 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; @@ -1034,7 +1040,7 @@ void HUD_Panel_Highlight(float allow_move) // 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; @@ -1046,7 +1052,7 @@ void HUD_Panel_Highlight(float allow_move) // 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; @@ -1055,7 +1061,7 @@ void HUD_Panel_Highlight(float allow_move) return; } } - highlightedPanel = -1; + highlightedPanel = world; highlightedAction = 0; } @@ -1063,8 +1069,7 @@ void HUD_Panel_EnableMenu() { 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() @@ -1094,21 +1099,21 @@ 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(); @@ -1124,9 +1129,12 @@ void HUD_Panel_Mouse() } } 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) @@ -1171,7 +1179,7 @@ void HUD_Panel_Mouse() 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 diff --git a/qcsrc/client/main.qh b/qcsrc/client/main.qh index 28536c256b..8369a5ff20 100644 --- a/qcsrc/client/main.qh +++ b/qcsrc/client/main.qh @@ -38,16 +38,6 @@ float gametype; //.float ctf_state; //.float health; -// Constants -const float COLOR_TEAM_RED = 64; -const float COLOR_TEAM_BLUE = 208; - -const float COLOR_TEAM1 = 4; // red -const float COLOR_TEAM2 = 13; // blue -const float COLOR_TEAM3 = 12; // yellow -const float COLOR_TEAM4 = 9; // pink -const float COLOR_SPECTATOR = 1337; - #define FONT_DEFAULT 0 #define FONT_USER 8 diff --git a/qcsrc/client/miscfunctions.qc b/qcsrc/client/miscfunctions.qc index 7edabdfc52..7951962e6b 100644 --- a/qcsrc/client/miscfunctions.qc +++ b/qcsrc/client/miscfunctions.qc @@ -108,7 +108,7 @@ entity GetTeam(float Team, float add) { float num; entity tm; - num = (Team == COLOR_SPECTATOR) ? 16 : Team; + num = (Team == NUM_SPECTATOR) ? 16 : Team; if(teamslots[num]) return teamslots[num]; if not(add) @@ -164,20 +164,6 @@ string ColorTranslateRGB(string s) return s; } -string Team_ColorCode(float teamid) -{ - if (teamid == COLOR_TEAM1) - return "^1"; - else if (teamid == COLOR_TEAM2) - return "^4"; - else if (teamid == COLOR_TEAM3) - return "^3"; - else if (teamid == COLOR_TEAM4) - return "^6"; - else - return "^7"; -} - // decolorizes and team colors the player name when needed string playername(string thename, float teamid) { diff --git a/qcsrc/client/progs.src b/qcsrc/client/progs.src index 9d968f1fe7..3b8aa1bace 100644 --- a/qcsrc/client/progs.src +++ b/qcsrc/client/progs.src @@ -14,7 +14,9 @@ Defs.qc ../warpzonelib/common.qh ../warpzonelib/client.qh +../common/teams.qh ../common/util.qh +../common/counting.qh ../common/items.qh ../common/explosion_equation.qh ../common/mapinfo.qh @@ -28,6 +30,9 @@ command/cl_cmd.qh autocvars.qh +../common/notifications.qh // must be after autocvars +../common/deathtypes.qh // must be after notifications + damage.qh ../csqcmodellib/interpolate.qh @@ -39,7 +44,6 @@ movetypes.qh prandom.qh bgmscript.qh noise.qh -teamplay.qh tturrets.qh ../server/tturrets/include/turrets_early.qh ../server/movelib.qc @@ -54,7 +58,6 @@ player_skeleton.qh sortlist.qc miscfunctions.qc -teamplay.qc ../server/t_items.qc teamradar.qc @@ -97,6 +100,7 @@ bgmscript.qc noise.qc ../common/util.qc +../common/notifications.qc ../common/command/markup.qc ../common/command/rpn.qc ../common/command/generic.qc diff --git a/qcsrc/client/scoreboard.qc b/qcsrc/client/scoreboard.qc index 1aa1b6a435..2ec7db0623 100644 --- a/qcsrc/client/scoreboard.qc +++ b/qcsrc/client/scoreboard.qc @@ -152,16 +152,16 @@ float HUD_ComparePlayerScores(entity left, entity right) vr = GetPlayerColor(right.sv_entnum); if(!left.gotscores) - vl = COLOR_SPECTATOR; + vl = NUM_SPECTATOR; if(!right.gotscores) - vr = COLOR_SPECTATOR; + vr = NUM_SPECTATOR; if(vl > vr) return true; if(vl < vr) return false; - if(vl == COLOR_SPECTATOR) + if(vl == NUM_SPECTATOR) { // FIRST the one with scores (spectators), THEN the ones without (downloaders) // no other sorting @@ -207,9 +207,9 @@ float HUD_CompareTeamScores(entity left, entity right) { float i, r; - if(left.team == COLOR_SPECTATOR) + if(left.team == NUM_SPECTATOR) return 1; - if(right.team == COLOR_SPECTATOR) + if(right.team == NUM_SPECTATOR) return 0; r = HUD_CompareScore(left.teamscores[ts_primary], right.teamscores[ts_primary], teamscores_flags[ts_primary]); @@ -669,11 +669,11 @@ string HUD_FixScoreboardColumnWidth(float i, string str) void HUD_PrintScoreboardItem(vector pos, entity pl, float is_self, float pl_number) { vector tmp, rgb; - rgb = GetTeamRGB(pl.team); + rgb = Team_ColorRGB(pl.team); string str; float i, field; float is_spec; - is_spec = (GetPlayerColor(pl.sv_entnum) == COLOR_SPECTATOR); + is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR); if((rgb == '1 1 1') && (!is_spec)) { rgb_x = autocvar_scoreboard_color_bg_r + 0.5; @@ -917,7 +917,7 @@ vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_siz else for(pl = players.sort_next; pl; pl = pl.sort_next) { - if(pl.team == COLOR_SPECTATOR) + if(pl.team == NUM_SPECTATOR) continue; HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i); pos_y += 1.25 * hud_fontsize_y; @@ -1120,7 +1120,7 @@ vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_ return pos; float is_spec; - is_spec = (GetPlayerColor(pl.sv_entnum) == COLOR_SPECTATOR); + is_spec = (GetPlayerColor(pl.sv_entnum) == NUM_SPECTATOR); vector hl_rgb; hl_rgb_x = autocvar_scoreboard_color_bg_r + 0.5; hl_rgb_y = autocvar_scoreboard_color_bg_g + 0.5; @@ -1148,7 +1148,7 @@ vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_ if (t == 0) continue; n = grecordholder[i]; - p = race_PlaceName(i+1); + p = count_ordinal(i+1); if(grecordholder[i] == GetPlayerName(player_localnum)) drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL); else if(!mod(i, 2) && scoreboard_highlight) @@ -1237,11 +1237,11 @@ void HUD_DrawScoreboard() team_score_baseoffset = eY * (2 * autocvar_scoreboard_border_thickness + hud_fontsize_y) - eX * (autocvar_scoreboard_border_thickness + hud_fontsize_x * 0.25); for(tm = teams.sort_next; tm; tm = tm.sort_next) { - if(tm.team == COLOR_SPECTATOR) + if(tm.team == NUM_SPECTATOR) continue; draw_beginBoldFont(); - rgb = GetTeamRGB(tm.team); + rgb = Team_ColorRGB(tm.team); str = ftos(tm.(teamscores[ts_primary])); drawstring(pos + team_score_baseoffset - eX * stringwidth(str, FALSE, hud_fontsize * 1.5), str, hud_fontsize * 1.5, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL); @@ -1273,7 +1273,7 @@ void HUD_DrawScoreboard() for(tm = teams.sort_next; tm; tm = tm.sort_next) { - if(tm.team == COLOR_SPECTATOR) + if(tm.team == NUM_SPECTATOR) continue; pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size); @@ -1293,14 +1293,14 @@ void HUD_DrawScoreboard() } else if(autocvar_scoreboard_accuracy && spectatee_status != -1 && !warmup_stage) { if(teamplay) - pos = HUD_DrawScoreboardAccuracyStats(pos, GetTeamRGB(myteam), bg_size); + pos = HUD_DrawScoreboardAccuracyStats(pos, Team_ColorRGB(myteam), bg_size); else pos = HUD_DrawScoreboardAccuracyStats(pos, rgb, bg_size); } if(teamplay) - pos = HUD_DrawMapStats(pos, GetTeamRGB(myteam), bg_size); + pos = HUD_DrawMapStats(pos, Team_ColorRGB(myteam), bg_size); else pos = HUD_DrawMapStats(pos, rgb, bg_size); @@ -1310,7 +1310,7 @@ void HUD_DrawScoreboard() tmp = pos; for(pl = players.sort_next; pl; pl = pl.sort_next) { - if(pl.team != COLOR_SPECTATOR) + if(pl.team != NUM_SPECTATOR) continue; pos_y += 1.25 * hud_fontsize_y; HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), specs); @@ -1393,10 +1393,24 @@ void HUD_DrawScoreboard() respawn_time *= -1; // remove mark now that we checked it respawn_time = max(time, respawn_time); // don't show a negative value while the server is respawning the player (lag) - str = sprintf(_("^1Respawning in ^3%s^1 seconds..."), ftos_decimals(respawn_time - time, autocvar_scoreboard_respawntime_decimals)); + str = sprintf(_("^1Respawning in ^3%s^1..."), + (autocvar_scoreboard_respawntime_decimals ? + count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals) + : + count_seconds(respawn_time - time) + ) + ); } else if(time < respawn_time) - str = sprintf(_("You are dead, wait ^3%s^7 seconds before respawning"), ftos_decimals(respawn_time - time, autocvar_scoreboard_respawntime_decimals)); + { + str = sprintf(_("You are dead, wait ^3%s^7 before respawning"), + (autocvar_scoreboard_respawntime_decimals ? + count_seconds_decs(respawn_time - time, autocvar_scoreboard_respawntime_decimals) + : + count_seconds(respawn_time - time) + ) + ); + } else if(time >= respawn_time) str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump")); diff --git a/qcsrc/client/shownames.qc b/qcsrc/client/shownames.qc index 8b4f7a09f6..f20f143b03 100644 --- a/qcsrc/client/shownames.qc +++ b/qcsrc/client/shownames.qc @@ -187,7 +187,7 @@ void Draw_ShowNames_All() { float t; t = GetPlayerColor(i); - if(t == COLOR_SPECTATOR) + if(t == NUM_SPECTATOR) continue; entity e; diff --git a/qcsrc/client/teamplay.qc b/qcsrc/client/teamplay.qc deleted file mode 100644 index 80d89318f4..0000000000 --- a/qcsrc/client/teamplay.qc +++ /dev/null @@ -1,69 +0,0 @@ -float TeamByColor(float color) -{ - switch(color) - { - case COLOR_TEAM1: return 0; - case COLOR_TEAM2: return 1; - case COLOR_TEAM3: return 2; - case COLOR_TEAM4: return 3; - default: return 0; - } -} -float ColorByTeam(float i) -{ - switch(i) - { - case 0: return COLOR_TEAM1; - case 1: return COLOR_TEAM2; - case 2: return COLOR_TEAM3; - case 3: return COLOR_TEAM4; - default: return COLOR_TEAM1; - } -} - -float GetPlayerColorForce(float i) -{ - if(!teamplay) - return 0; - else - return stof(getplayerkeyvalue(i, "colors")) & 15; -} - -float GetPlayerColor(float i) -{ - if not(playerslots[i].gotscores) // unconnected - return COLOR_SPECTATOR; - else if(stof(getplayerkeyvalue(i, "frags")) == FRAGS_SPECTATOR) - return COLOR_SPECTATOR; - else - return GetPlayerColorForce(i); -} - -string GetPlayerName(float i) -{ - return ColorTranslateRGB(getplayerkeyvalue(i, "name")); -} - -vector GetTeamRGB(float color) -{ - switch(color) - { - default: return '1 1 1'; - case COLOR_TEAM1: return '1 0 0'; // red - case COLOR_TEAM2: return '0 0 1'; // blue - case COLOR_TEAM3: return '1 1 0'; // yellow - case COLOR_TEAM4: return '1 0 1'; // pink - } -} - -string GetTeamName(float color) -{ - switch(color) - { - default: return _("Spectators"); - case COLOR_TEAM1: return _("Red Team"); - case COLOR_TEAM2: return _("Blue Team"); - case COLOR_TEAM3: return _("Yellow Team"); - case COLOR_TEAM4: return _("Pink Team"); - } -} diff --git a/qcsrc/client/teamplay.qh b/qcsrc/client/teamplay.qh deleted file mode 100644 index 83359906bc..0000000000 --- a/qcsrc/client/teamplay.qh +++ /dev/null @@ -1,2 +0,0 @@ -float teamplay; -float myteam; diff --git a/qcsrc/client/tturrets.qc b/qcsrc/client/tturrets.qc index 6f3b030502..24deed681f 100644 --- a/qcsrc/client/tturrets.qc +++ b/qcsrc/client/tturrets.qc @@ -163,22 +163,22 @@ void turret_changeteam() { switch(self.team - 1) { - case COLOR_TEAM1: // Red + case NUM_TEAM_1: // Red self.glowmod = '2 0 0'; self.teamradar_color = '1 0 0'; break; - case COLOR_TEAM2: // Blue + case NUM_TEAM_2: // Blue self.glowmod = '0 0 2'; self.teamradar_color = '0 0 1'; break; - case COLOR_TEAM3: // Yellow + case NUM_TEAM_3: // Yellow self.glowmod = '1 1 0'; self.teamradar_color = '1 1 0'; break; - case COLOR_TEAM4: // Pink + case NUM_TEAM_4: // Pink self.glowmod = '1 0 1'; self.teamradar_color = '1 0 1'; break; diff --git a/qcsrc/client/waypointsprites.qc b/qcsrc/client/waypointsprites.qc index 7e9b91d6b8..2066aec68c 100644 --- a/qcsrc/client/waypointsprites.qc +++ b/qcsrc/client/waypointsprites.qc @@ -423,7 +423,7 @@ void Draw_WaypointSprite() spriteimage = self.netname; break; case SPRITERULE_TEAMPLAY: - if(t == COLOR_SPECTATOR + 1) + if(t == NUM_SPECTATOR + 1) spriteimage = self.netname3; else if(self.team == t) spriteimage = self.netname2; diff --git a/qcsrc/common/command/generic.qc b/qcsrc/common/command/generic.qc index fe176e3167..3059916c61 100644 --- a/qcsrc/common/command/generic.qc +++ b/qcsrc/common/command/generic.qc @@ -93,7 +93,7 @@ void GenericCommand_addtolist(float request, float argc) } } -void GenericCommand_curl(float request, float argc) +void GenericCommand_qc_curl(float request, float argc) { switch(request) { @@ -166,7 +166,7 @@ void GenericCommand_curl(float request, float argc) default: case CMD_REQUEST_USAGE: { - print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " curl [--key N] [--cvar] [--exec] URL [postargs...]")); + print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " qc_curl [--key N] [--cvar] [--exec] URL [postargs...]")); return; } } @@ -227,6 +227,56 @@ void GenericCommand_dumpcommands(float request) } } +void GenericCommand_dumpnotifs(float request) +{ + switch(request) + { + case CMD_REQUEST_COMMAND: + { + #ifndef MENUQC + float fh, alsoprint = FALSE; + string filename = argv(1); + + if(filename == "") + { + filename = "notifications.cfg"; + alsoprint = FALSE; + } + else if(filename == "-") + { + filename = "notifications.cfg"; + alsoprint = TRUE; + } + fh = fopen(filename, FILE_WRITE); + + if(fh >= 0) + { + Dump_Notifications(fh, alsoprint); + print(sprintf("Dumping notifications... File located in ^2data/data/%s^7.\n", filename)); + fclose(fh); + } + else + { + print(sprintf("^1Error: ^7Could not open file '%s'!\n", filename)); + } + #else + print(_("Notification dump command only works with cl_cmd and sv_cmd.\n")); + #endif + return; + } + + default: + case CMD_REQUEST_USAGE: + { + print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " dumpnotifs [filename]")); + print(" Where 'filename' is the file to write (default is notifications.cfg),\n"); + print(" if supplied with '-' output to console as well as default,\n"); + print(" if left blank, it will only write to default.\n"); + return; + } + } +} + void GenericCommand_maplist(float request, float argc) { switch(request) @@ -376,6 +426,47 @@ void GenericCommand_removefromlist(float request, float argc) } } +void GenericCommand_restartnotifs(float request) +{ + switch(request) + { + case CMD_REQUEST_COMMAND: + { + #ifndef MENUQC + print(sprintf( + strcat( + "Restart_Notifications(): Restarting %d notifications... ", + "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 + )); + Destroy_All_Notifications(); + CALL_ACCUMULATED_FUNCTION(RegisterNotifications); + #else + print(_("Notification restart command only works with cl_cmd and sv_cmd.\n")); + #endif + return; + } + + default: + case CMD_REQUEST_USAGE: + { + print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " restartnotifs")); + print(" No arguments required.\n"); + return; + } + } +} + void GenericCommand_settemp(float request, float argc) { switch(request) @@ -464,11 +555,13 @@ void GenericCommand_(float request) // Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;) #define GENERIC_COMMANDS(request,arguments,command) \ GENERIC_COMMAND("addtolist", GenericCommand_addtolist(request, arguments), "Add a string to a cvar") \ - GENERIC_COMMAND("curl", GenericCommand_curl(request, arguments), "Queries an URL") \ GENERIC_COMMAND("dumpcommands", GenericCommand_dumpcommands(request), "Dump all commands on the program to *_cmd_dump.txt") \ + GENERIC_COMMAND("dumpnotifs", GenericCommand_dumpnotifs(request), "Dump all notifications into notifications_dump.txt") \ GENERIC_COMMAND("maplist", GenericCommand_maplist(request, arguments), "Automatic control of maplist") \ GENERIC_COMMAND("nextframe", GenericCommand_nextframe(request, arguments, command), "Execute the given command next frame of this VM") \ + GENERIC_COMMAND("qc_curl", GenericCommand_qc_curl(request, arguments), "Queries a URL") \ GENERIC_COMMAND("removefromlist", GenericCommand_removefromlist(request, arguments), "Remove a string from a cvar") \ + GENERIC_COMMAND("restartnotifs", GenericCommand_restartnotifs(request), "Re-initialize all notifications") \ GENERIC_COMMAND("rpn", GenericCommand_rpn(request, arguments, command), "RPN calculator") \ GENERIC_COMMAND("settemp", GenericCommand_settemp(request, arguments), "Temporarily set a value to a cvar which is restored later") \ GENERIC_COMMAND("settemp_restore", GenericCommand_settemp_restore(request, arguments), "Restore all cvars set by settemp command") \ diff --git a/qcsrc/common/constants.qh b/qcsrc/common/constants.qh index cdc58cb554..cbda9dcdd5 100644 --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@ -36,17 +36,13 @@ const float TE_CSQC_NEXGUNBEAMPARTICLE = 104; const float TE_CSQC_LIGHTNINGARC = 105; const float TE_CSQC_TEAMNAGGER = 106; const float TE_CSQC_PINGPLREPORT = 107; -const float TE_CSQC_ANNOUNCE = 110; -const float TE_CSQC_TARGET_MUSIC = 111; -const float TE_CSQC_KILLNOTIFY = 112; -const float TE_CSQC_KILLCENTERPRINT = 113; -const float TE_CSQC_CENTERPRINT_GENERIC = 114; -const float TE_CSQC_WEAPONCOMPLAIN = 115; -const float TE_CSQC_NEX_SCOPE = 116; -const float TE_CSQC_MINELAYER_MAXMINES = 117; -const float TE_CSQC_HAGAR_MAXROCKETS = 118; -const float TE_CSQC_VEHICLESETUP = 119; -const float TE_CSQC_SVNOTICE = 120; +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; @@ -99,6 +95,7 @@ const float ENT_CLIENT_WARPZONE_TELEPORTED = 32; const float ENT_CLIENT_MODEL = 33; const float ENT_CLIENT_ITEM = 34; const float ENT_CLIENT_BUMBLE_RAYGUN = 35; +const float ENT_CLIENT_NOTIFICATION = 36; const float ENT_CLIENT_TURRET = 40; const float ENT_CLIENT_AUXILIARYXHAIR = 50; @@ -180,6 +177,7 @@ const float STAT_SECRETS_TOTAL = 70; 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; @@ -364,85 +362,6 @@ float SPECIES_ROBOT_RUSTY = 4; float SPECIES_ROBOT_SHINY = 5; float SPECIES_RESERVED = 15; -// Deathtypes (weapon deathtypes are the IT_* constants below) -// NOTE: when adding death types, please add an explanation to Docs/spamlog.txt too. -float DEATH_SPECIAL_START = 10000; -float DEATH_FALL = 10000; -float DEATH_TELEFRAG = 10001; -float DEATH_DROWN = 10002; -float DEATH_HURTTRIGGER = 10003; -float DEATH_LAVA = 10004; -float DEATH_SLIME = 10005; -float DEATH_KILL = 10006; -float DEATH_NOAMMO = 10007; -float DEATH_SWAMP = 10008; -float DEATH_TEAMCHANGE = 10009; -float DEATH_AUTOTEAMCHANGE = 10010; -float DEATH_CAMP = 10011; -float DEATH_SHOOTING_STAR = 10012; -float DEATH_ROT = 10013; -float DEATH_MIRRORDAMAGE = 10014; -float DEATH_TOUCHEXPLODE = 10015; -float DEATH_CHEAT = 10016; -float DEATH_FIRE = 10017; -float DEATH_QUIET = 10021; - -float DEATH_VHFIRST = 10030; -float DEATH_VHCRUSH = 10030; -float DEATH_SBMINIGUN = 10031; -float DEATH_SBROCKET = 10032; -float DEATH_SBBLOWUP = 10033; -float DEATH_WAKIGUN = 10034; -float DEATH_WAKIROCKET = 10035; -float DEATH_WAKIBLOWUP = 10036; -float DEATH_RAPTOR_CANNON = 10037; -float DEATH_RAPTOR_BOMB = 10038; -float DEATH_RAPTOR_BOMB_SPLIT = 10039; -float DEATH_RAPTOR_DEATH = 10040; -float DEATH_BUMB_GUN = 10041; -float DEATH_BUMB_RAY = 10042; -float DEATH_BUMB_RAY_HEAL = 10043; -float DEATH_BUMB_DEATH = 10044; -float DEATH_VHLAST = 10044; -#define DEATH_ISVEHICLE(t) ((t) >= DEATH_VHFIRST && (t) <= DEATH_VHLAST) - -float DEATH_GENERIC = 10050; - -float DEATH_WEAPON = 10100; - -float DEATH_CUSTOM = 10300; - -float DEATH_TURRET = 10500; -float DEATH_TURRET_EWHEEL = 10501; -float DEATH_TURRET_FLAC = 10502; -float DEATH_TURRET_MACHINEGUN = 10503; -float DEATH_TURRET_WALKER_GUN = 10504; -float DEATH_TURRET_WALKER_MEELE = 10505; -float DEATH_TURRET_WALKER_ROCKET = 10506; -float DEATH_TURRET_HELLION = 10507; -float DEATH_TURRET_HK = 10508; -float DEATH_TURRET_MLRS = 10509; -float DEATH_TURRET_PLASMA = 10510; -float DEATH_TURRET_PHASER = 10511; -float DEATH_TURRET_TESLA = 10512; -float DEATH_TURRET_LAST = 10512; - -float DEATH_WEAPONMASK = 0xFF; -float DEATH_HITTYPEMASK = 0x1F00; // which is WAY below 10000 used for normal deaths -float HITTYPE_SECONDARY = 0x100; -float HITTYPE_SPLASH = 0x200; // automatically set by RadiusDamage -float HITTYPE_BOUNCE = 0x400; -float HITTYPE_RESERVED2 = 0x800; -float HITTYPE_RESERVED = 0x1000; // unused yet - -// macros to access these -#define DEATH_ISTURRET(t) ((t) >= DEATH_TURRET && (t) <= DEATH_TURRET_LAST) -#define DEATH_ISSPECIAL(t) ((t) >= DEATH_SPECIAL_START) -#define DEATH_WEAPONOFWEAPONDEATH(t) ((t) & DEATH_WEAPONMASK) -#define DEATH_ISWEAPON(t,w) (!DEATH_ISSPECIAL(t) && DEATH_WEAPONOFWEAPONDEATH(t) == (w)) -#define DEATH_WEAPONOF(t) (DEATH_ISSPECIAL(t) ? 0 : DEATH_WEAPONOFWEAPONDEATH(t)) -#define WEP_VALID(w) ((w) >= WEP_FIRST && (w) <= WEP_LAST) - #define FRAGS_PLAYER 0 #define FRAGS_SPECTATOR -666 #define FRAGS_LMS_LOSER -616 @@ -457,62 +376,6 @@ float WATERLEVEL_SUBMERGED = 3; float MAX_SHOT_DISTANCE = 32768; -//centerprint ID list -float CPID_TEAMCHANGE = 1; -float CPID_CTF_CAPTURESHIELD = 2; -float CPID_MINSTA_FINDAMMO = 3; -float CPID_NIX_WPNCHANGE = 4; -float CPID_DISCONNECT_IDLING = 5; -float CPID_ROUND_STARTING = 6; -float CPID_GAME_STARTING = 7; -float CPID_TIMEOUT_COUNTDOWN = 8; -float CPID_MOTD = 9; -float CPID_KH_MSG = 10; -float CPID_PREVENT_JOIN = 11; - -// CSQC centerprint/notify message types -float MSG_SUICIDE = 0; -float MSG_KILL = 1; -float MSG_SPREE = 2; -float MSG_KILL_ACTION = 3; -float MSG_KILL_ACTION_SPREE = 4; -float MSG_INFO = 5; -float MSG_KA = 6; -float MSG_RACE = 10; - -float KILL_TEAM_RED = 12001; -float KILL_TEAM_BLUE = 12002; -float KILL_TEAM_SPREE = 12003; -float KILL_FIRST_BLOOD = 12004; -float KILL_FIRST_VICTIM = 12005; -float KILL_TYPEFRAG = 12006; -float KILL_TYPEFRAGGED = 12007; -float KILL_FRAG = 12008; -float KILL_FRAGGED = 12009; -float KILL_SPREE = 12010; -float KILL_END_SPREE = 12011; -float KILL_SPREE_3 = 12012; -float KILL_SPREE_5 = 12013; -float KILL_SPREE_10 = 12014; -float KILL_SPREE_15 = 12015; -float KILL_SPREE_20 = 12016; -float KILL_SPREE_25 = 12017; -float KILL_SPREE_30 = 12018; - -float INFO_GOTFLAG = 13001; -float INFO_PICKUPFLAG = 13002; -float INFO_LOSTFLAG = 13003; -float INFO_RETURNFLAG = 13004; -float INFO_CAPTUREFLAG = 13005; - -float KA_PICKUPBALL = 14001; -float KA_DROPBALL = 14002; - -float RACE_SERVER_RECORD = 15001; -float RACE_NEW_TIME = 15002; -float RACE_NEW_RANK = 15003; -float RACE_FAIL = 15004; - // weapon requests float WR_SETUP = 1; // (SVQC) setup weapon data float WR_THINK = 2; // (SVQC) logic to run every frame @@ -520,8 +383,8 @@ float WR_CHECKAMMO1 = 3; // (SVQC) checks ammo for weapon float WR_CHECKAMMO2 = 4; // (SVQC) checks ammo for weapon float WR_AIM = 5; // (SVQC) runs bot aiming code for this weapon float WR_PRECACHE = 6; // (CSQC and SVQC) precaches models/sounds used by this weapon -float WR_SUICIDEMESSAGE = 7; // (CSQC) sets w_deathtypestring or leaves it alone (and may inspect w_deathtype for details) -float WR_KILLMESSAGE = 8; // (CSQC) sets w_deathtypestring or leaves it alone +float WR_SUICIDEMESSAGE = 7; // (SVQC) notification number for suicide message (may inspect w_deathtype for details) +float WR_KILLMESSAGE = 8; // (SVQC) notification number for kill message (may inspect w_deathtype for details) float WR_RELOAD = 9; // (SVQC) does not need to do anything float WR_RESETPLAYER = 10; // (SVQC) does not need to do anything float WR_IMPACTEFFECT = 11; // (CSQC) impact effect @@ -529,43 +392,6 @@ float WR_SWITCHABLE = 12; // (CSQC) impact effect 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 diff --git a/qcsrc/common/counting.qh b/qcsrc/common/counting.qh new file mode 100644 index 0000000000..a74f74e980 --- /dev/null +++ b/qcsrc/common/counting.qh @@ -0,0 +1,199 @@ +// =============================================== +// Time processing and counting functions/macros +// =============================================== + +#define count_years_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s years")), ftos_decimals(time, decs)) +#define count_years(time) count_fill(time, \ + ZCTX(_("CI_ZER^%d years")), /* zeroth */ \ + ZCTX(_("CI_FIR^%d year")), /* first */ \ + ZCTX(_("CI_SEC^%d years")), /* year */ \ + ZCTX(_("CI_THI^%d years")), /* third */ \ + ZCTX(_("CI_MUL^%d years"))) /* multi */ + +#define count_weeks_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s weeks")), ftos_decimals(time, decs)) +#define count_weeks(time) count_fill(time, \ + ZCTX(_("CI_ZER^%d weeks")), /* zeroth */ \ + ZCTX(_("CI_FIR^%d week")), /* first */ \ + ZCTX(_("CI_SEC^%d weeks")), /* week */ \ + ZCTX(_("CI_THI^%d weeks")), /* third */ \ + ZCTX(_("CI_MUL^%d weeks"))) /* multi */ + +#define count_days_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s days")), ftos_decimals(time, decs)) +#define count_days(time) count_fill(time, \ + ZCTX(_("CI_ZER^%d days")), /* zeroth */ \ + ZCTX(_("CI_FIR^%d day")), /* first */ \ + ZCTX(_("CI_SEC^%d days")), /* day */ \ + ZCTX(_("CI_THI^%d days")), /* third */ \ + ZCTX(_("CI_MUL^%d days"))) /* multi */ + +#define count_hours_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s hours")), ftos_decimals(time, decs)) +#define count_hours(time) count_fill(time, \ + ZCTX(_("CI_ZER^%d hours")), /* zeroth */ \ + ZCTX(_("CI_FIR^%d hour")), /* first */ \ + ZCTX(_("CI_SEC^%d hours")), /* hour */ \ + ZCTX(_("CI_THI^%d hours")), /* third */ \ + ZCTX(_("CI_MUL^%d hours"))) /* multi */ + + +#define count_minutes_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s minutes")), ftos_decimals(time, decs)) +#define count_minutes(time) count_fill(time, \ + ZCTX(_("CI_ZER^%d minutes")), /* zeroth */ \ + ZCTX(_("CI_FIR^%d minute")), /* first */ \ + ZCTX(_("CI_SEC^%d minutes")), /* minute */ \ + ZCTX(_("CI_THI^%d minutes")), /* third */ \ + ZCTX(_("CI_MUL^%d minutes"))) /* multi */ + +#define count_seconds_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s seconds")), ftos_decimals(time, decs)) +#define count_seconds(time) count_fill(time, \ + ZCTX(_("CI_ZER^%d seconds")), /* zeroth */ \ + ZCTX(_("CI_FIR^%d second")), /* first */ \ + ZCTX(_("CI_SEC^%d seconds")), /* second */ \ + ZCTX(_("CI_THI^%d seconds")), /* third */ \ + ZCTX(_("CI_MUL^%d seconds"))) /* multi */ + +string count_ordinal(float interval) +{ + // This function is designed primarily for the English language, it's impossible + // to accomodate all languages unless we do a specific function for each one... + // and since that's not technically feasible/practical, this is all we've got folks. + + // Basically, it just allows you to represent a number or count in different ways + // depending on the number... like, with count_ordinal you can provide integers + // and retrieve 1st, 2nd, 3rd, nth ordinal numbers in a clean and simple way. + if(floor((mod(interval, 100))/10) * 10 != 10) // examples: 12th, 111th, 213th will not execute this block + { + // otherwise, check normally for 1st,2nd,3rd insertions + switch(mod(interval, 10)) + { + case 1: return sprintf(_("%dst"), interval); + case 2: return sprintf(_("%dnd"), interval); + case 3: return sprintf(_("%drd"), interval); + default: return sprintf(_("%dth"), interval); + } + } + else { return sprintf(_("%dth"), interval); } + + return ""; +} + +string count_fill(float interval, string zeroth, string first, string second, string third, string multi) +{ + // This function is designed primarily for the English language, it's impossible + // to accomodate all languages unless we do a specific function for each one... + // and since that's not technically feasible/practical, this is all we've got folks. + + // Here you can insert specific strings based on the interval number, so you could do + // i.e. count_seconds which outputs like this: + // 0 seconds + // 1 second + // 2 seconds + // 3 seconds + // etc... minutes, hours, days, etc. + + switch(floor(interval)) + { + case 0: return sprintf(zeroth, interval); + case 1: + { + if(interval == 1) // EXACTLY value of 1 + return sprintf(first, interval); + else + return sprintf(multi, interval); + } + case 2: return sprintf(second, interval); + case 3: return sprintf(third, interval); + default: return sprintf(multi, interval); + } + return ""; +} + +string process_time(float outputtype, float seconds) +{ + float tmp_hours = 0, tmp_minutes = 0, tmp_seconds = 0; + float tmp_years = 0, tmp_weeks = 0, tmp_days = 0; + + tmp_seconds = floor(seconds); + + if(tmp_seconds) + { + tmp_minutes = floor(tmp_seconds / 60); + + if(tmp_minutes) + { + tmp_seconds -= (tmp_minutes * 60); + tmp_hours = floor(tmp_minutes / 60); + + if(tmp_hours) + { + tmp_minutes -= (tmp_hours * 60); + tmp_days = floor(tmp_hours / 24); + + if(tmp_days) + { + tmp_hours -= (tmp_days * 24); + tmp_weeks = floor(tmp_days / 7); + + if(tmp_weeks) + { + tmp_days -= (tmp_weeks * 7); + tmp_years = floor(tmp_weeks / 52); + } + } + } + } + } + + switch(outputtype) + { + case 1: return sprintf("%02d:%02d:%02d", tmp_hours, tmp_minutes, tmp_seconds); + case 2: + { + string output = ""; + + output = count_seconds(tmp_seconds); + + if(tmp_minutes) + { + output = sprintf( + "%s%s", + count_minutes(tmp_minutes), + ((output != "") ? sprintf(", %s", output) : "")); + } + + if(tmp_hours) + { + output = sprintf( + "%s%s", + count_hours(tmp_hours), + ((output != "") ? sprintf(", %s", output) : "")); + } + + if(tmp_days) + { + output = sprintf( + "%s%s", + count_days(tmp_days), + ((output != "") ? sprintf(", %s", output) : "")); + } + + if(tmp_weeks) + { + output = sprintf( + "%s%s", + count_weeks(tmp_weeks), + ((output != "") ? sprintf(", %s", output) : "")); + } + + if(tmp_years) + { + output = sprintf( + "%s%s", + count_years(tmp_years), + ((output != "") ? sprintf(", %s", output) : "")); + } + + return output; + } + } + return ""; +} diff --git a/qcsrc/common/deathtypes.qh b/qcsrc/common/deathtypes.qh new file mode 100644 index 0000000000..f9a9ceba25 --- /dev/null +++ b/qcsrc/common/deathtypes.qh @@ -0,0 +1,112 @@ +// ================================ +// Deathtypes, reworked by Samual +// ================================ + +#define DEATHTYPES \ + DEATHTYPE(DEATH_AUTOTEAMCHANGE, DEATH_SELF_AUTOTEAMCHANGE, NO_MSG, DEATH_SPECIAL_START) \ + DEATHTYPE(DEATH_CAMP, DEATH_SELF_CAMP, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_CHEAT, DEATH_SELF_CHEAT, DEATH_MURDER_CHEAT, NORMAL_POS) \ + DEATHTYPE(DEATH_CUSTOM, DEATH_SELF_CUSTOM, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_DROWN, DEATH_SELF_DROWN, DEATH_MURDER_DROWN, NORMAL_POS) \ + DEATHTYPE(DEATH_FALL, DEATH_SELF_FALL, DEATH_MURDER_FALL, NORMAL_POS) \ + DEATHTYPE(DEATH_FIRE, DEATH_SELF_FIRE, DEATH_MURDER_FIRE, NORMAL_POS) \ + DEATHTYPE(DEATH_GENERIC, DEATH_SELF_GENERIC, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_HURTTRIGGER, DEATH_SELF_VOID, DEATH_MURDER_VOID, NORMAL_POS) \ + DEATHTYPE(DEATH_KILL, DEATH_SELF_SUICIDE, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_LAVA, DEATH_SELF_LAVA, DEATH_MURDER_LAVA, NORMAL_POS) \ + DEATHTYPE(DEATH_MIRRORDAMAGE, DEATH_SELF_BETRAYAL, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_NOAMMO, DEATH_SELF_NOAMMO, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_ROT, DEATH_SELF_ROT, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_SHOOTING_STAR, DEATH_SELF_SHOOTING_STAR, DEATH_MURDER_SHOOTING_STAR, NORMAL_POS) \ + DEATHTYPE(DEATH_SLIME, DEATH_SELF_SLIME, DEATH_MURDER_SLIME, NORMAL_POS) \ + DEATHTYPE(DEATH_SWAMP, DEATH_SELF_SWAMP, DEATH_MURDER_SWAMP, NORMAL_POS) \ + DEATHTYPE(DEATH_TEAMCHANGE, DEATH_SELF_TEAMCHANGE, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_TELEFRAG, NO_MSG, DEATH_MURDER_TELEFRAG, NORMAL_POS) \ + DEATHTYPE(DEATH_TOUCHEXPLODE, DEATH_SELF_TOUCHEXPLODE, DEATH_MURDER_TOUCHEXPLODE, NORMAL_POS) \ + DEATHTYPE(DEATH_TURRET, DEATH_SELF_TURRET, NO_MSG, DEATH_TURRET_FIRST) \ + DEATHTYPE(DEATH_TURRET_EWHEEL, DEATH_SELF_TURRET_EWHEEL, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_TURRET_FLAC, DEATH_SELF_TURRET_FLAC, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_TURRET_HELLION, DEATH_SELF_TURRET_HELLION, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_TURRET_HK, DEATH_SELF_TURRET_HK, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_TURRET_MACHINEGUN, DEATH_SELF_TURRET_MACHINEGUN, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_TURRET_MLRS, DEATH_SELF_TURRET_MLRS, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_TURRET_PHASER, DEATH_SELF_TURRET_PHASER, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_TURRET_PLASMA, DEATH_SELF_TURRET_PLASMA, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_TURRET_TESLA, DEATH_SELF_TURRET_TESLA, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_TURRET_WALK_GUN, DEATH_SELF_TURRET_WALK_GUN, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_TURRET_WALK_MEELE, DEATH_SELF_TURRET_WALK_MEELE, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_TURRET_WALK_ROCKET, DEATH_SELF_TURRET_WALK_ROCKET, NO_MSG, DEATH_TURRET_LAST) \ + DEATHTYPE(DEATH_VH_BUMB_DEATH, DEATH_SELF_VH_BUMB_DEATH, DEATH_MURDER_VH_BUMB_DEATH, DEATH_VHFIRST) \ + DEATHTYPE(DEATH_VH_BUMB_GUN, NO_MSG, DEATH_MURDER_VH_BUMB_GUN, NORMAL_POS) \ + DEATHTYPE(DEATH_VH_CRUSH, DEATH_SELF_VH_CRUSH, DEATH_MURDER_VH_CRUSH, NORMAL_POS) \ + DEATHTYPE(DEATH_VH_RAPT_BOMB, DEATH_SELF_VH_RAPT_BOMB, DEATH_MURDER_VH_RAPT_BOMB, NORMAL_POS) \ + DEATHTYPE(DEATH_VH_RAPT_CANNON, NO_MSG, DEATH_MURDER_VH_RAPT_CANNON, NORMAL_POS) \ + DEATHTYPE(DEATH_VH_RAPT_DEATH, DEATH_SELF_VH_RAPT_DEATH, DEATH_MURDER_VH_RAPT_DEATH, NORMAL_POS) \ + DEATHTYPE(DEATH_VH_RAPT_FRAGMENT, DEATH_SELF_VH_RAPT_BOMB, DEATH_MURDER_VH_RAPT_BOMB, NORMAL_POS) \ + DEATHTYPE(DEATH_VH_SPID_DEATH, DEATH_SELF_VH_SPID_DEATH, DEATH_MURDER_VH_SPID_DEATH, NORMAL_POS) \ + DEATHTYPE(DEATH_VH_SPID_MINIGUN, NO_MSG, DEATH_MURDER_VH_SPID_MINIGUN, NORMAL_POS) \ + DEATHTYPE(DEATH_VH_SPID_ROCKET, DEATH_SELF_VH_SPID_ROCKET, DEATH_MURDER_VH_SPID_ROCKET, NORMAL_POS) \ + DEATHTYPE(DEATH_VH_WAKI_DEATH, DEATH_SELF_VH_WAKI_DEATH, DEATH_MURDER_VH_WAKI_DEATH, NORMAL_POS) \ + DEATHTYPE(DEATH_VH_WAKI_GUN, NO_MSG, DEATH_MURDER_VH_WAKI_GUN, NORMAL_POS) \ + DEATHTYPE(DEATH_VH_WAKI_ROCKET, DEATH_SELF_VH_WAKI_ROCKET, DEATH_MURDER_VH_WAKI_ROCKET, DEATH_VHLAST) \ + DEATHTYPE(DEATH_WEAPON, NO_MSG, NO_MSG, NORMAL_POS) + +#define DT_FIRST 10000 +#define DT_MAX 128 // limit of recursive functions with ACCUMULATE_FUNCTION +float DT_COUNT; + +entity deathtypes[DT_MAX]; +.entity death_msgself; +.entity death_msgmurder; + +#define DEATHTYPE(name,msg_death,msg_death_by,position) \ + float name; \ + float position; \ + void RegisterDeathtype_##name() \ + { \ + SET_FIRST_OR_LAST(position, DT_FIRST, DT_COUNT) \ + SET_FIELD_COUNT(name, DT_FIRST, DT_COUNT) \ + CHECK_MAX_COUNT(name, DT_MAX, DT_COUNT, "deathtypes") \ + \ + entity deathent = spawn(); \ + deathtypes[(name - DT_FIRST)] = deathent; \ + deathent.classname = "deathtype"; \ + deathent.nent_name = #name; \ + #if (msg_death != NO_MSG) \ + deathent.death_msgself = msg_multi_notifs[msg_death - 1]; \ + #endif \ + #if (msg_death_by != NO_MSG) \ + deathent.death_msgmurder = msg_multi_notifs[msg_death_by - 1]; \ + #endif \ + } \ + ACCUMULATE_FUNCTION(RegisterDeathtypes, RegisterDeathtype_##name) + +DEATHTYPES +#undef DEATHTYPE + +#define DEATH_ISSPECIAL(t) ((t) >= DEATH_SPECIAL_START) +#define DEATH_ISVEHICLE(t) ((t) >= DEATH_VHFIRST && (t) <= DEATH_VHLAST) +#define DEATH_ISTURRET(t) ((t) >= DEATH_TURRET_FIRST && (t) <= DEATH_TURRET_LAST) +#define DEATH_WEAPONOFWEAPONDEATH(t) ((t) & DEATH_WEAPONMASK) +#define DEATH_ISWEAPON(t,w) (!DEATH_ISSPECIAL(t) && DEATH_WEAPONOFWEAPONDEATH(t) == (w)) +#define DEATH_WEAPONOF(t) (DEATH_ISSPECIAL(t) ? 0 : DEATH_WEAPONOFWEAPONDEATH(t)) +#define WEP_VALID(w) ((w) >= WEP_FIRST && (w) <= WEP_LAST) + +string Deathtype_Name(float deathtype) +{ + if(DEATH_ISSPECIAL(deathtype)) + { + entity deathent = deathtypes[(deathtype - DT_FIRST)]; + if not(deathent) { backtrace("Deathtype_Name: Could not find deathtype entity!\n"); return ""; } + return deathent.nent_name; + } + else { return ftos(deathtype); } +} + +float DEATH_WEAPONMASK = 0xFF; +float DEATH_HITTYPEMASK = 0x1F00; // which is WAY below 10000 used for normal deaths +float HITTYPE_SECONDARY = 0x100; +float HITTYPE_SPLASH = 0x200; // automatically set by RadiusDamage +float HITTYPE_BOUNCE = 0x400; +float HITTYPE_RESERVED2 = 0x800; +float HITTYPE_RESERVED = 0x1000; // unused yet diff --git a/qcsrc/common/items.qc b/qcsrc/common/items.qc index 0aebde0af2..c961895d95 100644 --- a/qcsrc/common/items.qc +++ b/qcsrc/common/items.qc @@ -172,3 +172,13 @@ void W_RandomWeapons(entity e, float n) } WEPSET_COPY_EA(e, result); } + +string W_Name(float weaponid) +{ + return (get_weaponinfo(weaponid)).message; +} + +float W_AmmoItemCode(float wpn) +{ + return (get_weaponinfo(wpn)).items & IT_AMMO; +} diff --git a/qcsrc/common/items.qh b/qcsrc/common/items.qh index c20715d585..ba42d55ac6 100644 --- a/qcsrc/common/items.qh +++ b/qcsrc/common/items.qh @@ -242,3 +242,7 @@ string W_FixWeaponOrder_AllowIncomplete(string order); string W_FixWeaponOrder_ForceComplete(string order); void W_RandomWeapons(entity e, float n); + +string W_Name(float weaponid); + +float W_AmmoItemCode(float wpn); diff --git a/qcsrc/common/mapinfo.qc b/qcsrc/common/mapinfo.qc index f7ced42057..82c5673d8b 100644 --- a/qcsrc/common/mapinfo.qc +++ b/qcsrc/common/mapinfo.qc @@ -313,8 +313,6 @@ float _MapInfo_Generate(string pFilename) // 0: failure, 1: ok ent, 2: ok bsp MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTF; else if(v == "team_CTF_blueflag") MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTF; - else if(v == "runematch_spawn_point") - MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_RUNEMATCH; else if(v == "target_assault_roundend") MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ASSAULT; else if(v == "onslaught_generator") @@ -364,7 +362,6 @@ float _MapInfo_Generate(string pFilename) // 0: failure, 1: ok ent, 2: ok bsp else { MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DEATHMATCH; // DM always works - MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_RUNEMATCH; // Rune always works MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_LMS; // LMS always works MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_KEEPAWAY; // Keepaway always works @@ -418,7 +415,6 @@ string _MapInfo_GetDefault(float t) case MAPINFO_TYPE_TEAM_DEATHMATCH: return "50 20 2 0"; case MAPINFO_TYPE_DOMINATION: return "200 20 0"; case MAPINFO_TYPE_CTF: return "300 20 10 0"; - case MAPINFO_TYPE_RUNEMATCH: return "200 20 0"; case MAPINFO_TYPE_LMS: return "9 20 0"; case MAPINFO_TYPE_ARENA: return "10 20 0"; case MAPINFO_TYPE_CA: return "10 20 0"; @@ -480,6 +476,22 @@ void _MapInfo_Map_ApplyGametype(string s, float pWantedType, float pThisType, fl 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); @@ -570,6 +582,8 @@ void _MapInfo_Map_ApplyGametypeEx(string s, float pWantedType, float pThisType) 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")); @@ -617,6 +631,8 @@ void _MapInfo_Map_ApplyGametypeEx(string s, float pWantedType, float pThisType) 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); } diff --git a/qcsrc/common/mapinfo.qh b/qcsrc/common/mapinfo.qh index bd67f67a82..10a35ee470 100644 --- a/qcsrc/common/mapinfo.qh +++ b/qcsrc/common/mapinfo.qh @@ -42,9 +42,6 @@ REGISTER_GAMETYPE(_("Last Man Standing"),lms,g_lms,LMS,"timelimit=20 lives=9 lea REGISTER_GAMETYPE(_("Arena"),arena,g_arena,ARENA,"timelimit=20 pointlimit=10 leadlimit=0") #define g_arena IS_GAMETYPE(ARENA) -REGISTER_GAMETYPE(_("Runematch"),rune,g_runematch,RUNEMATCH,"timelimit=20 pointlimit=200 leadlimit=0") -#define g_runematch IS_GAMETYPE(RUNEMATCH) - REGISTER_GAMETYPE(_("Race"),rc,g_race,RACE,"timelimit=20 qualifying_timelimit=5 laplimit=7 teamlaplimit=15 leadlimit=0") #define g_race IS_GAMETYPE(RACE) diff --git a/qcsrc/common/notifications.qc b/qcsrc/common/notifications.qc new file mode 100644 index 0000000000..b72380ccee --- /dev/null +++ b/qcsrc/common/notifications.qc @@ -0,0 +1,1572 @@ +// ================================================ +// Unified notification system, written by Samual +// Last updated: March, 2013 +// ================================================ + +string Get_Notif_TypeName(float net_type) +{ + 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"; + case MSG_MULTI: return "MSG_MULTI"; + } + backtrace(sprintf("Get_Notif_TypeName(%d): Improper net type!\n", net_type)); + return ""; +} + +entity Get_Notif_Ent(float net_type, float net_name) +{ + 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]; + } + backtrace(sprintf("Get_Notif_Ent(%d, %d): Improper net type!\n", net_type, net_name)); + return world; +} + +string Notification_CheckArgs_TypeName(float net_type, float net_name) +{ + // check supplied type and name for errors + string checkargs = ""; + #define CHECKARG_TYPENAME(type) case MSG_##type##: \ + { if(!net_name || (net_name > NOTIF_##type##_COUNT)) \ + { checkargs = sprintf("Improper name: %d!", net_name); } break; } + switch(net_type) + { + CHECKARG_TYPENAME(ANNCE) + CHECKARG_TYPENAME(INFO) + CHECKARG_TYPENAME(CENTER) + CHECKARG_TYPENAME(MULTI) + default: { checkargs = sprintf("Improper type: %d!", checkargs, net_type); break; } + } + #undef CHECKARG_TYPENAME + return checkargs; +} + +#ifdef SVQC +string Notification_CheckArgs( + float broadcast, entity client, + float net_type, float net_name) +{ + // check supplied broadcast, target, type, and name for errors + string checkargs = Notification_CheckArgs_TypeName(net_type, net_name); + if(checkargs != "") { checkargs = strcat(checkargs, " "); } + switch(broadcast) + { + case NOTIF_ONE: + case NOTIF_ONE_ONLY: + { + if(IS_NOT_A_CLIENT(client)) + { checkargs = sprintf("%sNo client provided!", checkargs); } + break; + } + + case NOTIF_ALL_EXCEPT: + { + if(IS_NOT_A_CLIENT(client)) + { checkargs = sprintf("%sException can't be a non-client!", checkargs); } + break; + } + + case NOTIF_ALL: + { + if(client) + { checkargs = sprintf("%sEntity provided when world was required!", checkargs); } + break; + } + + case NOTIF_TEAM: + case NOTIF_TEAM_EXCEPT: + { + if not(teamplay) { checkargs = sprintf("%sTeamplay not active!", checkargs); } + else if(IS_NOT_A_CLIENT(client)) + { + if(broadcast == NOTIF_TEAM) { checkargs = sprintf("%sNo client provided!", checkargs); } + else { checkargs = sprintf("%sException can't be a non-client!", checkargs); } + } + break; + } + + default: { checkargs = sprintf("%sImproper broadcast: %d!", checkargs, broadcast); break; } + } + return checkargs; +} +#endif + +// =============================== +// Initialization Core Functions +// =============================== + +// used by restartnotifs command to initialize notifications +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); } + if(notif.nent_durcnt != "") { strunzone(notif.nent_durcnt); } + if(notif.nent_string != "") { strunzone(notif.nent_string); } + remove(notif); +} + +void Destroy_All_Notifications(void) +{ + entity notif; + float i; + + #define DESTROY_LOOP(type,count) \ + for(i = 1; i <= count; ++i) \ + { \ + notif = Get_Notif_Ent(type, i); \ + if not(notif) { backtrace("Destroy_All_Notifications(): Missing notification entity!\n"); return; } \ + Destroy_Notification_Entity(notif); \ + } + + // kill all networked notifications and centerprints + #ifdef SVQC + Kill_Notification(NOTIF_ALL, world, 0, 0); + #else + reset_centerprint_messages(); + #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) + #undef DESTROY_LOOP +} + +string Process_Notif_Line( + float msg_is_info, + float chat, + string input, + string notiftype, + string notifname, + string stringtype) +{ + if(msg_is_info) + { + #ifdef CSQC + if((chat && autocvar_notification_allow_chatboxprint) + || (autocvar_notification_allow_chatboxprint == 2)) + { + // pass 1: add ETX char at beginning of line + input = strcat("\{3}", input); + + // pass 2: add ETX char at end of each new line (so that + // messages with multiple lines are put through chatbox too) + input = strreplace("\n", "\n\{3}", input); + + // pass 3: strip trailing ETX char + if(substring(input, (strlen(input) - 1), 1) == "\{3}") + { input = substring(input, 0, (strlen(input) - 1)); } + } + #endif + if(substring(input, (strlen(input) - 1), 1) != "\n") + { + print(sprintf( + strcat( + "^1MISSING/BROKEN NEW LINE AT END OF NOTIFICATION: ", + "^7net_type = %s, net_name = %s, string = %s.\n" + ), + notiftype, + notifname, + stringtype + )); + notif_error = TRUE; + return strcat(input, "\n"); + } + } + return input; +} + +string Process_Notif_Args( + float arg_type, + string args, + string notiftype, + string notifname) +{ + string selected, remaining = args; + float sel_num = 0; + + for(;(remaining != "");) + { + selected = car(remaining); remaining = cdr(remaining); + + switch(arg_type) + { + case 1: // normal args + { + if(sel_num == NOTIF_MAX_ARGS) + { + print(sprintf( + strcat( + "^1NOTIFICATION HAS TOO MANY ARGUMENTS: ", + "^7net_type = %s, net_name = %s, max args = %d.\n" + ), + notiftype, + notifname, + NOTIF_MAX_ARGS + )); + notif_error = TRUE; + break; + } + + switch(strtolower(selected)) + { + #define ARG_CASE(prog,selected,result) \ + #if (prog != ARG_DC) \ + case selected: { ++sel_num; break; } \ + #endif + NOTIF_ARGUMENT_LIST + #undef ARG_CASE + default: + { + print(sprintf( + strcat( + "^1NOTIFICATION WITH UNKNOWN TOKEN IN ARGUMENT STRING: ", + "^7net_type = %s, net_name = %s, args arg = '%s'.\n" + ), + notiftype, + notifname, + selected + )); + notif_error = TRUE; + break; + } + } + break; + } + case 2: // hudargs + { + if(sel_num == NOTIF_MAX_HUDARGS) + { + print(sprintf( + strcat( + "^1NOTIFICATION HAS TOO MANY ARGUMENTS: ", + "^7net_type = %s, net_name = %s, max hudargs = %d.\n" + ), + notiftype, + notifname, + NOTIF_MAX_HUDARGS + )); + notif_error = TRUE; + break; + } + + switch(strtolower(selected)) + { + #define ARG_CASE(prog,selected,result) \ + #if (prog == ARG_CS_SV_HA) \ + case selected: { ++sel_num; break; } \ + #endif + NOTIF_ARGUMENT_LIST + #undef ARG_CASE + default: + { + print(sprintf( + strcat( + "^1NOTIFICATION WITH UNKNOWN TOKEN IN ARGUMENT STRING: ", + "^7net_type = %s, net_name = %s, hudargs arg = '%s'.\n" + ), + notiftype, + notifname, + selected + )); + notif_error = TRUE; + break; + } + } + break; + } + case 3: // durcnt + { + if(sel_num == NOTIF_MAX_DURCNT) + { + print(sprintf( + strcat( + "^1NOTIFICATION HAS TOO MANY ARGUMENTS: ", + "^7net_type = %s, net_name = %s, max durcnt = %d.\n" + ), + notiftype, + notifname, + NOTIF_MAX_DURCNT + )); + notif_error = TRUE; + break; + } + + switch(strtolower(selected)) + { + #define ARG_CASE(prog,selected,result) \ + #if (prog == ARG_CS_SV_DC) || (prog == ARG_DC) \ + case selected: { ++sel_num; break; } \ + #endif + NOTIF_ARGUMENT_LIST + #undef ARG_CASE + default: + { + if(ftos(stof(selected)) != "") { ++sel_num; } + else + { + print(sprintf( + strcat( + "^1NOTIFICATION WITH UNKNOWN TOKEN IN ARGUMENT STRING: ", + "^7net_type = %s, net_name = %s, durcnt arg = '%s'.\n" + ), + notiftype, + notifname, + selected + )); + notif_error = TRUE; + } + break; + } + } + break; + } + } + } + return args; +} + +void Create_Notification_Entity( + float var_default, + float var_cvar, + 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 hudargs, + string icon, + float cpid, + string durcnt, + string normal, + string gentle, + float msg_is_info, + float msg_is_multi) +{ + // ===================== + // Global Entity Setup + // ===================== + entity notif = spawn(); + 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"; + msg_info_notifs[nameid - 1] = notif; + notif.classname = "msg_info_notification"; + break; + } + case MSG_CENTER: + { + typestring = "MSG_CENTER"; + msg_center_notifs[nameid - 1] = notif; + notif.classname = "msg_center_notification"; + break; + } + case MSG_MULTI: + { + typestring = "MSG_MULTI"; + msg_multi_notifs[nameid - 1] = notif; + notif.classname = "MSG_MULTI_notification"; + break; + } + + default: + { + error(sprintf( + strcat( + "^1NOTIFICATION WITH IMPROPER TYPE: ", + "^7net_type = %d, net_name = %s.\n" + ), + typeid, + namestring + )); + return; // It's not possible to recover from this one + } + } + notif.nent_default = var_default; + notif.nent_name = strzone(namestring); + notif.nent_id = nameid; + notif.nent_enabled = (1 <= var_cvar); + + // Other pre-notif-setup requisites + notif_error = FALSE; + + // ==================== + // Notification Setup + // ==================== + if(msg_is_multi) + { + // Set MSG_MULTI string/float counts + if((anncename == NO_MSG) && (infoname == NO_MSG) && (centername == NO_MSG)) + { + print(sprintf( + strcat( + "^1NOTIFICATION WITH NO SUBCALLS: ", + "^7net_type = %s, net_name = %s.\n" + ), + typestring, + namestring + )); + notif_error = TRUE; + } + 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; + + if(infoname != NO_MSG) + { + notif.nent_msginfo = msg_info_notifs[infoname - 1]; + infoname_stringcount = notif.nent_msginfo.nent_stringcount; + infoname_floatcount = notif.nent_msginfo.nent_floatcount; + } + + if(centername != NO_MSG) + { + notif.nent_msgcenter = msg_center_notifs[centername - 1]; + centername_stringcount = notif.nent_msgcenter.nent_stringcount; + centername_floatcount = notif.nent_msgcenter.nent_floatcount; + } + + // set the requirements of THIS notification to the totals of its subcalls + notif.nent_stringcount = max(infoname_stringcount, centername_stringcount); + 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 + notif.nent_stringcount = strnum; + notif.nent_floatcount = flnum; + + // Only initialize arguments if we're either a client or on a dedicated server + #ifdef SVQC + float should_process_args = server_is_dedicated; + #else + float should_process_args = TRUE; + #endif + + if(should_process_args) + { + // ======================== + // Process Main Arguments + // ======================== + if(strnum + flnum) + { + if(args != "") + { + notif.nent_args = strzone( + Process_Notif_Args(1, args, typestring, namestring)); + } + else if((hudargs == "") && (durcnt =="")) + { + print(sprintf( + strcat( + "^1NOTIFICATION HAS ARG COUNTS BUT NO ARGS OR HUDARGS OR DURCNT: ", + "^7net_type = %s, net_name = %s, strnum = %d, flnum = %d\n" + ), + typestring, + namestring, + strnum, + flnum + )); + notif_error = TRUE; + } + } + else if(args != "") + { + notif.nent_args = strzone( + Process_Notif_Args(1, args, typestring, namestring)); + } + + + // ======================================= + // Process HUD and Centerprint Arguments + // Only processed on CSQC, as these + // args are only for HUD features. + // ======================================= + #ifdef CSQC + if(hudargs != "") + { + notif.nent_hudargs = strzone( + Process_Notif_Args(2, hudargs, typestring, namestring)); + + if(icon != "") { notif.nent_icon = strzone(icon); } + else + { + print(sprintf( + strcat( + "^1NOTIFICATION HAS HUDARGS BUT NO ICON: ", + "^7net_type = %s, net_name = %s.\n" + ), + typestring, + namestring + )); + notif_error = TRUE; + } + } + else if(icon != "") + { + print(sprintf( + strcat( + "^1NOTIFICATION HAS ICON BUT NO HUDARGS: ", + "^7net_type = %s, net_name = %s.\n" + ), + typestring, + namestring + )); + notif_error = TRUE; + } + + if(durcnt != "") + { + notif.nent_durcnt = strzone( + Process_Notif_Args(3, durcnt, typestring, namestring)); + + if(cpid != NO_MSG) { notif.nent_cpid = cpid; } + else + { + print(sprintf( + strcat( + "^1NOTIFICATION HAS DURCNT BUT NO CPID: ", + "^7net_type = %s, net_name = %s.\n" + ), + typestring, + namestring + )); + notif_error = TRUE; + } + } + else if(cpid != NO_MSG) { notif.nent_cpid = cpid; } + #endif + + + // ====================== + // Process Notif String + // ====================== + #define SET_NOTIF_STRING(string,stringname) \ + notif.nent_string = strzone(CCR( \ + Process_Notif_Line( \ + msg_is_info, \ + (var_cvar > 1), \ + string, \ + typestring, \ + namestring, \ + stringname \ + )) \ + ); + + if(GENTLE) + { + if(gentle != "") { SET_NOTIF_STRING(gentle, "GENTLE") } + else if(normal != "") { SET_NOTIF_STRING(normal, "NORMAL") } + } + else if(normal != "") { SET_NOTIF_STRING(normal, "NORMAL") } + + #undef SET_NOTIF_STRING + + // Check to make sure a string was chosen + if(notif.nent_string == "") + { + print(sprintf( + strcat( + "^1EMPTY NOTIFICATION: ", + "^7net_type = %s, net_name = %s.\n" + ), + typestring, + namestring + )); + notif_error = TRUE; + } + } + } + + // now check to see if any errors happened + if(notif_error) + { + notif.nent_enabled = FALSE; // disable the notification so it can't cause trouble + notif_global_error = TRUE; // throw the red flag that an error happened on init + } +} + + +// ========================================= +// Cvar Handling With 'dumpnotifs' Command +// ========================================= + +void Dump_Notifications(float fh, float alsoprint) +{ + #define NOTIF_WRITE(a) { \ + fputs(fh, a); \ + if(alsoprint) { print(a); } } + #define NOTIF_WRITE_ENTITY(name,default,description) { \ + notif_msg = \ + sprintf( \ + "seta notification_%s \"%d\" \"%s\"\n", \ + name, default, description \ + ); \ + NOTIF_WRITE(notif_msg) } + #define NOTIF_WRITE_HARDCODED(cvar,default,description) { \ + notif_msg = \ + sprintf( \ + "seta notification_%s \"%s\" \"%s\"\n", \ + cvar, default, description \ + ); \ + NOTIF_WRITE(notif_msg) } + + string notif_msg; + float i; + entity e; + + // Note: This warning only applies to the notifications.cfg file that is output... + + // You ARE supposed to manually edit this function to add i.e. hard coded + // notification variables for mutators or game modes or such and then + // regenerate the notifications.cfg file from the new code. + + NOTIF_WRITE("// ********************************************** //\n"); + NOTIF_WRITE("// ** WARNING - DO NOT MANUALLY EDIT THIS FILE ** //\n"); + NOTIF_WRITE("// ** ** //\n"); + NOTIF_WRITE("// ** This file is automatically generated ** //\n"); + NOTIF_WRITE("// ** by code with the command 'dumpnotifs'. ** //\n"); + NOTIF_WRITE("// ** ** //\n"); + NOTIF_WRITE("// ** If you add a new notification, please ** //\n"); + NOTIF_WRITE("// ** regenerate this file with that command ** //\n"); + NOTIF_WRITE("// ** making sure that the output matches ** //\n"); + NOTIF_WRITE("// ** with the lists and defaults in code. ** //\n"); + NOTIF_WRITE("// ** ** //\n"); + NOTIF_WRITE("// ********************************************** //\n"); + + // These notifications will also append their string as a comment... + // 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) + { + e = Get_Notif_Ent(MSG_INFO, 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 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"); + } + + NOTIF_WRITE(sprintf("\n// MSG_CENTER notifications (count = %d):\n", NOTIF_CENTER_COUNT)); + for(i = 1; i <= NOTIF_CENTER_COUNT; ++i) + { + e = Get_Notif_Ent(MSG_CENTER, 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 = off, 1 = centerprint"); + } + + NOTIF_WRITE(sprintf("\n// MSG_MULTI notifications (count = %d):\n", NOTIF_MULTI_COUNT)); + for(i = 1; i <= NOTIF_MULTI_COUNT; ++i) + { + e = Get_Notif_Ent(MSG_MULTI, 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 = off, 1 = trigger subcalls"); + } + + // edit these to match whichever cvars are used for specific notification options + NOTIF_WRITE("\n// HARD CODED notification variables:\n"); + NOTIF_WRITE_HARDCODED("allow_chatboxprint", "1", "Allow notifications to be printed to chat box by setting notification cvar to 2 (You can also set this cvar to 2 to force ALL notifications to be printed to the chatbox)"); + 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_HARDCODED("lifetime_mapload", "10", "Amount of time that notification entities last immediately at mapload (in seconds) to help prevent notifications from being lost on early init (like gamestart countdown)"); + NOTIF_WRITE_HARDCODED("lifetime_runtime", "0.5", "Amount of time that notification entities last on the server during runtime (In seconds)"); + NOTIF_WRITE_HARDCODED("server_allows_frag_verbose", "1", "Server side cvar for showing extra information in frag messages... 0 = no extra frag information, 1 = frag information only in warmup, 2 = frag information allowed all the time"); + NOTIF_WRITE_HARDCODED("server_allows_location", "1", "Server side cvar for allowing death messages to show location information too"); + NOTIF_WRITE_HARDCODED("show_location", "0", "Append location information to MSG_INFO death/kill messages"); + NOTIF_WRITE_HARDCODED("show_location_string", "", "Replacement string piped into sprintf, so you can do different messages like this: ' at the %s' or ' (near %s)'"); + NOTIF_WRITE_HARDCODED("show_sprees", "1", "Print information about sprees in death/kill messages"); + NOTIF_WRITE_HARDCODED("show_sprees_center", "1", "Show spree information in MSG_CENTER messages... 0 = off, 1 = target (but only for first victim) and attacker"); + NOTIF_WRITE_HARDCODED("show_sprees_center_specialonly", "1", "Don't show spree information in MSG_CENTER messages if it isn't an achievement"); + NOTIF_WRITE_HARDCODED("show_sprees_info", "3", "Show spree information in MSG_INFO messages... 0 = off, 1 = target only, 2 = attacker only, 3 = target and attacker"); + NOTIF_WRITE_HARDCODED("show_sprees_info_newline", "1", "Show attacker spree information for MSG_INFO messages on a separate line than the death notification itself"); + NOTIF_WRITE_HARDCODED("show_sprees_info_specialonly", "1", "Don't show attacker spree information in MSG_INFO messages if it isn't an achievement"); + + NOTIF_WRITE(sprintf( + strcat( + "\n// Notification counts (total = %d): ", + "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 + )); + + return; + #undef NOTIF_WRITE_HARDCODED + #undef NOTIF_WRITE_ENTITY + #undef NOTIF_WRITE +} + +#ifdef SVQC +void Notification_GetCvars() +{ + GetCvars_handleFloat(get_cvars_s, get_cvars_f, FRAG_VERBOSE, "notification_frag_verbose"); +} +#endif + + +// =============================== +// 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 + Debug_Notification(sprintf( + "Local_Notification_sprintf('%s^7', '%s', %s, %s);\n", + MakeConsoleSafe(input), + args, + MakeConsoleSafe(sprintf("'%s^7', '%s^7', '%s^7', '%s^7'", s1, s2, s3, s4)), + sprintf("%d, %d, %d, %d", f1, f2, f3, f4) + )); + #endif + + string selected; + float sel_num; + for(sel_num = 0; sel_num < NOTIF_MAX_ARGS; ++sel_num) { arg_slot[sel_num] = ""; } + + string tmp_s; + + for(sel_num = 0;(args != "");) + { + selected = car(args); args = cdr(args); + NOTIF_HIT_MAX(NOTIF_MAX_ARGS, "Local_Notification_sprintf") + switch(strtolower(selected)) + { + #define ARG_CASE(prog,selected,result) \ + #ifdef CSQC \ + #if (prog != ARG_SV) && (prog != ARG_DC) \ + case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \ + #endif \ + #else \ + #if (prog != ARG_CS) && (prog != ARG_DC) \ + case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \ + #endif \ + #endif + NOTIF_ARGUMENT_LIST + #undef ARG_CASE + default: NOTIF_HIT_UNKNOWN(NOTIF_MAX_ARGS, "Local_Notification_sprintf") + } + } + return sprintf(input, arg_slot[0], arg_slot[1], arg_slot[2], arg_slot[3], arg_slot[4], arg_slot[5], arg_slot[6]); +} + +#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) +{ + string selected; + float sel_num; + arg_slot[0] = ""; arg_slot[1] = ""; + + for(sel_num = 0;(hudargs != "");) + { + selected = car(hudargs); hudargs = cdr(hudargs); + NOTIF_HIT_MAX(NOTIF_MAX_HUDARGS, "Local_Notification_HUD_Notify_Push") + switch(strtolower(selected)) + { + #define ARG_CASE(prog,selected,result) \ + #if (prog == ARG_CS_SV_HA) \ + case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \ + #endif + NOTIF_ARGUMENT_LIST + #undef ARG_CASE + default: NOTIF_HIT_UNKNOWN(NOTIF_MAX_HUDARGS, "Local_Notification_HUD_Notify_Push") + } + } + #ifdef NOTIFICATIONS_DEBUG + Debug_Notification(sprintf( + "Local_Notification_HUD_Notify_Push('%s^7', '%s', %s, %s);\n", + icon, + hudargs, + MakeConsoleSafe(sprintf("'%s^7', '%s^7', '%s^7', '%s^7'", s1, s2, s3, s4)), + MakeConsoleSafe(sprintf("'%s^7', '%s^7'", stof(arg_slot[0]), stof(arg_slot[1]))) + )); + #endif + HUD_Notify_Push(icon, arg_slot[0], arg_slot[1]); +} + +void Local_Notification_centerprint_generic( + string input, string durcnt, + float cpid, float f1, float f2) +{ + string selected; + float sel_num; + arg_slot[0] = ""; arg_slot[1] = ""; + + for(sel_num = 0;(durcnt != "");) + { + selected = car(durcnt); durcnt = cdr(durcnt); + NOTIF_HIT_MAX(NOTIF_MAX_DURCNT, "Local_Notification_centerprint_generic") + switch(strtolower(selected)) + { + #define ARG_CASE(prog,selected,result) \ + #if (prog == ARG_CS_SV_DC) || (prog == ARG_DC) \ + case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \ + #endif + NOTIF_ARGUMENT_LIST + #undef ARG_CASE + default: + { + if(ftos(stof(selected)) != "") { arg_slot[sel_num] = selected; ++sel_num; } + else { NOTIF_HIT_UNKNOWN(NOTIF_MAX_DURCNT, "Local_Notification_centerprint_generic") } + break; + } + } + } + #ifdef NOTIFICATIONS_DEBUG + Debug_Notification(sprintf( + "Local_Notification_centerprint_generic('%s^7', '%s', %d, %d, %d, %d);\n", + MakeConsoleSafe(input), + durcnt, + f1, f2, + stof(arg_slot[0]), stof(arg_slot[1]) + )); + #endif + centerprint_generic(cpid, input, stof(arg_slot[0]), stof(arg_slot[1])); +} +#endif + +void Local_Notification(float net_type, float net_name, ...count) +{ + // check supplied type and name for errors + string checkargs = Notification_CheckArgs_TypeName(net_type, net_name); + if(checkargs != "") { backtrace(sprintf("Incorrect usage of Local_Notification: %s\n", checkargs)); return; } + + entity notif = Get_Notif_Ent(net_type, net_name); + if not(notif) { backtrace("Local_Notification: Could not find notification entity!\n"); return; } + if not(notif.nent_enabled) + { + #ifdef NOTIFICATIONS_DEBUG + Debug_Notification(sprintf( + "Local_Notification(%s, %s): Entity was disabled...\n", + Get_Notif_TypeName(net_type), + notif.nent_name + )); + #endif + return; + } + + if((notif.nent_stringcount + notif.nent_floatcount) > count) + { + backtrace(sprintf( + strcat( + "Not enough arguments for Local_Notification(%s, %s, ...)! ", + "stringcount(%d) + floatcount(%d) > count(%d)\n", + "Check the definition and function call for accuracy...?\n" + ), + Get_Notif_TypeName(net_type), notif.nent_name, + notif.nent_stringcount, notif.nent_floatcount, count + )); + return; + } + else if((notif.nent_stringcount + notif.nent_floatcount) < count) + { + backtrace(sprintf( + strcat( + "Too many arguments for Local_Notification(%s, %s, ...)! ", + "stringcount(%d) + floatcount(%d) < count(%d)\n", + "Check the definition and function call for accuracy...?\n" + ), + Get_Notif_TypeName(net_type), notif.nent_name, + notif.nent_stringcount, notif.nent_floatcount, count + )); + return; + } + + string s1 = ((0 < notif.nent_stringcount) ? ...(0, string) : ""); + string s2 = ((1 < notif.nent_stringcount) ? ...(1, string) : ""); + string s3 = ((2 < notif.nent_stringcount) ? ...(2, string) : ""); + string s4 = ((3 < notif.nent_stringcount) ? ...(3, string) : ""); + float f1 = ((0 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 0), float) : 0); + 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); + + #ifdef NOTIFICATIONS_DEBUG + Debug_Notification(sprintf( + "Local_Notification(%s, %s, %s, %s);\n", + Get_Notif_TypeName(net_type), + notif.nent_name, + MakeConsoleSafe(sprintf("'%s^7', '%s^7', '%s^7', '%s^7'", s1, s2, s3, s4)), + sprintf("%d, %d, %d, %d", f1, f2, f3, f4) + )); + #endif + + 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( + Local_Notification_sprintf( + notif.nent_string, + notif.nent_args, + s1, s2, s3, s4, + f1, f2, f3, f4) + ); + #ifdef CSQC + if(notif.nent_icon != "") + { + Local_Notification_HUD_Notify_Push( + notif.nent_icon, + notif.nent_hudargs, + s1, s2, s3, s4); + } + #endif + break; + } + + #ifdef CSQC + case MSG_CENTER: + { + Local_Notification_centerprint_generic( + Local_Notification_sprintf( + notif.nent_string, + notif.nent_args, + s1, s2, s3, s4, + f1, f2, f3, f4), + notif.nent_durcnt, + notif.nent_cpid, + f1, f2); + break; + } + #endif + + case MSG_MULTI: + { + if(notif.nent_msginfo) + if(notif.nent_msginfo.nent_enabled) + { + Local_Notification_WOVA( + MSG_INFO, + notif.nent_msginfo.nent_id, + notif.nent_msginfo.nent_stringcount, + notif.nent_msginfo.nent_floatcount, + s1, s2, s3, s4, + 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) + { + Local_Notification_WOVA( + MSG_CENTER, + notif.nent_msgcenter.nent_id, + notif.nent_msgcenter.nent_stringcount, + notif.nent_msgcenter.nent_floatcount, + s1, s2, s3, s4, + f1, f2, f3, f4); + } + #endif + break; + } + } +} + +// WOVA = Without Variable Arguments +void Local_Notification_WOVA( + float net_type, float net_name, + float stringcount, float floatcount, + string s1, string s2, string s3, string s4, + float f1, float f2, float f3, float f4) +{ + #define VARITEM(stringc,floatc,args) \ + if((stringcount == stringc) && (floatcount == floatc)) \ + { Local_Notification(net_type, net_name, args); return; } + EIGHT_VARS_TO_VARARGS_VARLIST + #undef VARITEM + Local_Notification(net_type, net_name); // some notifications don't have any arguments at all +} + + +// ========================= +// Notification Networking +// ========================= + +#ifdef CSQC +void Read_Notification(float is_new) +{ + float net_type = ReadByte(); + float net_name = ReadShort(); + + entity notif; + + if(net_type == MSG_CENTER_CPID) + { + #ifdef NOTIFICATIONS_DEBUG + Debug_Notification(sprintf( + "Read_Notification(%d) at %f: net_type = %s, net_name = %d\n", + is_new, + time, + Get_Notif_TypeName(net_type), + net_name + )); + #endif + + if(is_new) + { + if(net_name == 0) { reset_centerprint_messages(); } + else if(net_name != NO_CPID) + { + // in this case, net_name IS the cpid we want to kill + centerprint_generic(net_name, "", 0, 0); + } + else + { + backtrace(sprintf( + "Read_Notification(%d) at %f: ^1TRIED TO KILL NO_CPID CENTERPRINT!\n", + is_new, + time + )); + } + } + } + else + { + notif = Get_Notif_Ent(net_type, net_name); + if not(notif) { backtrace("Read_Notification: Could not find notification entity!\n"); return; } + + #ifdef NOTIFICATIONS_DEBUG + Debug_Notification(sprintf( + "Read_Notification(%d) at %f: net_type = %s, net_name = %s\n", + is_new, + time, + Get_Notif_TypeName(net_type), + notif.nent_name + )); + #endif + + string s1 = ((0 < notif.nent_stringcount) ? ReadString() : ""); + string s2 = ((1 < notif.nent_stringcount) ? ReadString() : ""); + string s3 = ((2 < notif.nent_stringcount) ? ReadString() : ""); + string s4 = ((3 < notif.nent_stringcount) ? ReadString() : ""); + float f1 = ((0 < notif.nent_floatcount) ? ReadLong() : 0); + float f2 = ((1 < notif.nent_floatcount) ? ReadLong() : 0); + float f3 = ((2 < notif.nent_floatcount) ? ReadLong() : 0); + float f4 = ((3 < notif.nent_floatcount) ? ReadLong() : 0); + + if(is_new) + { + Local_Notification_WOVA( + net_type, net_name, + notif.nent_stringcount, + notif.nent_floatcount, + s1, s2, s3, s4, + f1, f2, f3, f4); + } + } +} +#endif + +#ifdef SVQC +void Net_Notification_Remove() +{ + if not(self) { backtrace(sprintf("Net_Notification_Remove() at %f: Missing self!?\n", time)); return; } + + #ifdef NOTIFICATIONS_DEBUG + Debug_Notification(sprintf( + "Net_Notification_Remove() at %f: %s '%s - %s' notification\n", + time, + ((self.nent_net_name == -1) ? "Killed" : "Removed"), + Get_Notif_TypeName(self.nent_net_type), + self.owner.nent_name + )); + #endif + + float i; + for(i = 0; i < 4; ++i) { if(self.nent_strings[i]) { strunzone(self.nent_strings[i]); } } + remove(self); +} + +float Net_Write_Notification(entity client, float sf) +{ + float i, send = FALSE; + + switch(self.nent_broadcast) + { + case NOTIF_ONE: // send to one client and their spectator + { + if( + (client == self.nent_client) + || + ( + IS_SPEC(client) + && + (client.enemy == self.nent_client) + ) + ) { send = TRUE; } + break; + } + case NOTIF_ONE_ONLY: // send ONLY to one client + { + if(client == self.nent_client) { send = TRUE; } + break; + } + case NOTIF_TEAM: // send only to X team and their spectators + { + if( + (client.team == self.nent_client.team) + || + ( + IS_SPEC(client) + && + (client.enemy.team == self.nent_client.team) + ) + ) { send = TRUE; } + break; + } + case NOTIF_TEAM_EXCEPT: // send only to X team and their spectators, except for Y person and their spectators + { + if( + (client != self.nent_client) + && + ( + (client.team == self.nent_client.team) + || + ( + IS_SPEC(client) + && + ( + (client.enemy != self.nent_client) + && + (client.enemy.team == self.nent_client.team) + ) + ) + ) + ) { send = TRUE; } + break; + } + case NOTIF_ALL: // send to everyone + { + send = TRUE; + break; + } + case NOTIF_ALL_EXCEPT: // send to everyone except X person and their spectators + { + if( + (client != self.nent_client) + && + !( + IS_SPEC(client) + && + (client.enemy == self.nent_client) + ) + ) { send = TRUE; } + break; + } + default: { send = FALSE; break; } + } + + if(send) + { + WriteByte(MSG_ENTITY, ENT_CLIENT_NOTIFICATION); + WriteByte(MSG_ENTITY, self.nent_net_type); + WriteShort(MSG_ENTITY, self.nent_net_name); + for(i = 0; i < self.nent_stringcount; ++i) { WriteString(MSG_ENTITY, self.nent_strings[i]); } + for(i = 0; i < self.nent_floatcount; ++i) { WriteLong(MSG_ENTITY, self.nent_floats[i]); } + } + + return send; +} + +void Kill_Notification( + float broadcast, entity client, + float net_type, float net_name) +{ + string checkargs = Notification_CheckArgs(broadcast, client, 1, 1); + if(checkargs != "") { backtrace(sprintf("Incorrect usage of Kill_Notification: %s\n", checkargs)); return; } + + #ifdef NOTIFICATIONS_DEBUG + Debug_Notification(sprintf( + "Kill_Notification(%d, '%s', %s, %d);\n", + broadcast, + client.netname, + (net_type ? Get_Notif_TypeName(net_type) : "0"), + net_name + )); + #endif + + entity notif, net_notif; + float killed_cpid = NO_CPID; + + switch(net_type) + { + case 0: + { + killed_cpid = 0; // kill ALL centerprints + break; + } + + case MSG_CENTER: + { + if(net_name) + { + entity notif = Get_Notif_Ent(net_type, net_name); + if not(notif) { backtrace("Kill_Notification: Could not find notification entity!\n"); return; } + + if(notif.nent_cpid) + killed_cpid = notif.nent_cpid; + else + killed_cpid = NO_CPID; + } + else + { + killed_cpid = 0; // kill ALL centerprints + } + break; + } + + case MSG_CENTER_CPID: + { + killed_cpid = net_name; + break; + } + } + + if(killed_cpid != NO_CPID) + { + net_notif = spawn(); + net_notif.classname = "net_kill_notification"; + net_notif.nent_broadcast = broadcast; + net_notif.nent_client = client; + net_notif.nent_net_type = MSG_CENTER_CPID; + net_notif.nent_net_name = killed_cpid; + Net_LinkEntity(net_notif, FALSE, autocvar_notification_lifetime_runtime, Net_Write_Notification); + } + + for(notif = world; (notif = find(notif, classname, "net_notification"));) + { + if(net_type) + { + if((killed_cpid != NO_CPID) && (notif.nent_net_type == MSG_CENTER)) + { + if(notif.owner.nent_cpid == killed_cpid) + { + notif.nent_net_name = -1; + notif.nextthink = time; + } + else { continue; } // we ARE looking for a specific CPID, don't kill everything else too + } + else if(notif.nent_net_type == net_type) + { + if(net_name) + { + if(notif.nent_net_name == net_name) { notif.nent_net_name = -1; notif.nextthink = time; } + else { continue; } // we ARE looking for a certain net_name, don't kill everything else too + } + else { notif.nent_net_name = -1; notif.nextthink = time; } + } + else { continue; } // we ARE looking for a certain net_type, don't kill everything else too + } + else { notif.nent_net_name = -1; notif.nextthink = time; } + } +} + +void Send_Notification( + float broadcast, entity client, + float net_type, float net_name, + ...count) +{ + // check supplied broadcast, target, type, and name for errors + string checkargs = Notification_CheckArgs(broadcast, client, net_type, net_name); + if(checkargs != "") { backtrace(sprintf("Incorrect usage of Send_Notification: %s\n", checkargs)); return; } + + // retreive counts for the arguments of this notification + entity notif = Get_Notif_Ent(net_type, net_name); + if not(notif) { backtrace("Send_Notification: Could not find notification entity!\n"); return; } + + if((notif.nent_stringcount + notif.nent_floatcount) > count) + { + backtrace(sprintf( + strcat( + "Not enough arguments for Send_Notification(%d, %s, %s, ...)! ", + "stringcount(%d) + floatcount(%d) > count(%d)\n", + "Check the definition and function call for accuracy...?\n" + ), + broadcast, Get_Notif_TypeName(net_type), notif.nent_name, + notif.nent_stringcount, notif.nent_floatcount, count + )); + return; + } + else if((notif.nent_stringcount + notif.nent_floatcount) < count) + { + backtrace(sprintf( + strcat( + "Too many arguments for Send_Notification(%d, %s, %s, ...)! ", + "stringcount(%d) + floatcount(%d) < count(%d)\n", + "Check the definition and function call for accuracy...?\n" + ), + broadcast, Get_Notif_TypeName(net_type), notif.nent_name, + notif.nent_stringcount, notif.nent_floatcount, count + )); + return; + } + + #ifdef NOTIFICATIONS_DEBUG + string s1 = ((0 < notif.nent_stringcount) ? ...(0, string) : ""); + string s2 = ((1 < notif.nent_stringcount) ? ...(1, string) : ""); + string s3 = ((2 < notif.nent_stringcount) ? ...(2, string) : ""); + string s4 = ((3 < notif.nent_stringcount) ? ...(3, string) : ""); + float f1 = ((0 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 0), float) : 0); + 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); + Debug_Notification(sprintf( + "Send_Notification(%d, %s, %s, %s, %s);\n", + broadcast, + Get_Notif_TypeName(net_type), + notif.nent_name, + MakeConsoleSafe(sprintf("'%s^7', '%s^7', '%s^7', '%s^7'", s1, s2, s3, s4)), + sprintf("%d, %d, %d, %d", f1, f2, f3, f4) + )); + #endif + + entity net_notif = spawn(); + net_notif.owner = notif; + net_notif.classname = "net_notification"; + net_notif.nent_broadcast = broadcast; + net_notif.nent_client = client; + net_notif.nent_net_type = net_type; + net_notif.nent_net_name = net_name; + net_notif.nent_stringcount = notif.nent_stringcount; + net_notif.nent_floatcount = notif.nent_floatcount; + + float i; + for(i = 0; i < net_notif.nent_stringcount; ++i) { net_notif.nent_strings[i] = strzone(...(i, string)); } + for(i = 0; i < net_notif.nent_floatcount; ++i) { net_notif.nent_floats[i] = ...((net_notif.nent_stringcount + i), float); } + + net_notif.think = Net_Notification_Remove; + net_notif.nextthink = + ((time > autocvar_notification_lifetime_mapload) + ? + (time + autocvar_notification_lifetime_runtime) + : + autocvar_notification_lifetime_mapload + ); + + Net_LinkEntity(net_notif, FALSE, 0, Net_Write_Notification); + + 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, + notif.nent_stringcount, + notif.nent_floatcount, + IFSTR(0), IFSTR(1), IFSTR(2), IFSTR(3), + IFFL(0), IFFL(1), IFFL(2), IFFL(3)); + } +} + +// WOVA = Without Variable Arguments +void Send_Notification_WOVA( + float broadcast, entity client, + float net_type, float net_name, + string s1, string s2, string s3, string s4, + float f1, float f2, float f3, float f4) +{ + entity notif = Get_Notif_Ent(net_type, net_name); + + #ifdef NOTIFICATIONS_DEBUG + Debug_Notification(sprintf( + "Send_Notification_WOVA(%d, %s, %s, %s, %s);\n", + broadcast, + Get_Notif_TypeName(net_type), + notif.nent_name, + MakeConsoleSafe(sprintf("'%s^7', '%s^7', '%s^7', '%s^7'", s1, s2, s3, s4)), + sprintf("%d, %d, %d, %d", f1, f2, f3, f4) + )); + #endif + + #define VARITEM(stringc,floatc,args) \ + if((notif.nent_stringcount == stringc) && (notif.nent_floatcount == floatc)) \ + { Send_Notification(broadcast, client, net_type, net_name, args); return; } + EIGHT_VARS_TO_VARARGS_VARLIST + #undef VARITEM + Send_Notification(broadcast, client, net_type, net_name); // some notifications don't have any arguments at all +} +#endif // ifdef SVQC diff --git a/qcsrc/common/notifications.qh b/qcsrc/common/notifications.qh new file mode 100644 index 0000000000..d1aeba001e --- /dev/null +++ b/qcsrc/common/notifications.qh @@ -0,0 +1,1259 @@ +// ================================================ +// Unified notification system, written by Samual +// Last updated: March, 2013 +// ================================================ + +// main types/groups of 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 + +#define EIGHT_VARS_TO_VARARGS_VARLIST \ + VARITEM(1, 0, s1) \ + VARITEM(2, 0, XPD(s1, s2)) \ + VARITEM(3, 0, XPD(s1, s2, s3)) \ + VARITEM(4, 0, XPD(s1, s2, s3, s4)) \ + VARITEM(0, 1, f1) \ + VARITEM(1, 1, XPD(s1, f1)) \ + VARITEM(2, 1, XPD(s1, s2, f1)) \ + VARITEM(3, 1, XPD(s1, s2, s3, f1)) \ + VARITEM(4, 1, XPD(s1, s2, s3, s4, f1)) \ + VARITEM(0, 2, XPD(f1, f2)) \ + VARITEM(1, 2, XPD(s1, f1, f2)) \ + VARITEM(2, 2, XPD(s1, s2, f1, f2)) \ + VARITEM(3, 2, XPD(s1, s2, s3, f1, f2)) \ + VARITEM(4, 2, XPD(s1, s2, s3, s4, f1, f2)) \ + VARITEM(0, 3, XPD(f1, f2, f3)) \ + VARITEM(1, 3, XPD(s1, f1, f2, f3)) \ + VARITEM(2, 3, XPD(s1, s2, f1, f2, f3)) \ + VARITEM(3, 3, XPD(s1, s2, s3, f1, f2, f3)) \ + VARITEM(4, 3, XPD(s1, s2, s3, s4, f1, f2, f3)) \ + VARITEM(0, 4, XPD(f1, f2, f3, f4)) \ + VARITEM(1, 4, XPD(s1, f1, f2, f3, f4)) \ + VARITEM(2, 4, XPD(s1, s2, f1, f2, f3, f4)) \ + VARITEM(3, 4, XPD(s1, s2, s3, f1, f2, f3, f4)) \ + VARITEM(4, 4, XPD(s1, s2, s3, s4, f1, f2, f3, f4)) + +void Destroy_All_Notifications(void); +void Create_Notification_Entity( + float var_default, + float var_cvar, + 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 hudargs, + string icon, + float cpid, + string durcnt, + string normal, + string gentle, + float msg_is_info, + float msg_is_multi); + +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, + float stringcount, float floatcount, + string s1, string s2, string s3, string s4, + float f1, float f2, float f3, float f4); + +#ifdef CSQC // CLIENT ONLY +void Read_Notification(float is_new); +string prev_soundfile; +float prev_soundtime; +#endif + +#ifdef SVQC // SERVER ONLY +#define NOTIF_ONE 1 +#define NOTIF_ONE_ONLY 2 +#define NOTIF_TEAM 3 +#define NOTIF_TEAM_EXCEPT 4 +#define NOTIF_ALL 5 +#define NOTIF_ALL_EXCEPT 6 + +#define IFSTR(num) ((num < notif.nent_stringcount) ? ...(num, string) : "") +#define IFFL(num) ((((notif.nent_stringcount-1) + num) < count) ? ...(((notif.nent_stringcount-1) + num), float) : 0) + +void Kill_Notification( + float broadcast, entity client, + float net_type, float net_name); +void Send_Notification( + float broadcast, entity client, + float net_type, float net_name, + ...count); +void Send_Notification_WOVA( + float broadcast, entity client, + float net_type, float net_name, + string s1, string s2, string s3, string s4, + float f1, float f2, float f3, float f4); +#endif + + +// ==================================== +// Notifications List and Information +// ==================================== +/* + List of all notifications (including identifiers and display information) + 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 + name: VAR: Name of notification + strnum: FLOAT: Number of STRING arguments (so that networking knows how many to send/receive) + flnum: FLOAT: Number of FLOAT arguments (so that networking knows how many to send/receive) + args: STRING: Arguments for Local_Notification_sprintf() + hudargs: STRING: Arguments for Local_Notification_HUD_Notify_Push() + icon: STRING: icon string name for the hud notify panel, "" if no icon is used + normal: STRING: Normal message (string for sprintf when gentle messages are NOT enabled) + gentle: STRING: Gentle message (string for sprintf when gentle messages ARE enabled) + MSG_CENTER: + default: FLOAT: Default setting for whether the notification is enabled or not + ^-> 0 = disabled, 1 = enabled + name: VAR: Name of notification + strnum: FLOAT: Number of STRING arguments (so that networking knows how many to send/receive) + flnum: FLOAT: Number of FLOAT arguments (so that networking knows how many to send/receive) + args: STRING: Arguments for Local_Notification_sprintf() + cpid: FLOAT: centerprint ID number (CPID_*), NO_CPID if no CPID is needed + durcnt: XPD(FLOAT, FLOAT): Duration/Countdown: extra arguments for centerprint messages + normal: STRING: Normal message (string for sprintf when gentle messages are NOT enabled) + gentle: STRING: Gentle message (string for sprintf when gentle messages ARE enabled) + MSG_MULTI: + 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 + + Messages with ^F1, ^BG, ^TC, etc etc in them will replace those strings + with colors according to the cvars the user has chosen. This allows for + users to create unique color profiles for their HUD, giving more customization + options to HUD designers and end users who want such a feature. + + Check out the definitions in util.qc/util.qh/teams.qh for string CCR(...) and + string TCR(...) to better understand how these code replacements work. + + Additionally, you can find all the definitions and explanations for + the argument values and what they return down below in this file. + + Guidlines for notification declaration (please try and follow these): + Specific rules: + -ALWAYS start the string with a color, preferably background. + -ALWAYS reset a color after a name (this way they don't set it for the whole string). + -NEVER re-declare an event twice. + -NEVER add or remove tokens from the format, it SHOULD already work. + -MSG_INFO messages must ALWAYS end with a new line: \n + -MSG_INFO hudargs must always be ATTACKER -> VICTIM + -MSG_CENTER should NOT end with a new line + + General rules: + -Be clean and simple with your notification naming, + nothing too long for the name field... Abbreviations are your friend. :D + -Keep the spacing as clean as possible... if the arguments are abnormally long, + it's okay to go out of line a bit... but try and keep it clean still. + - Use ONLY spaces for spacing in the notification list, tabs are too inconsistent + with keeping alignment on different mediums. + -Sort the notifications in the most appropriate order for their tasks. + -ARIRE unir frk jvgu lbhe bja zbgure. (gvc sbe zvxrrhfn) -- Don't pay attention to this ^_^ + + Final note: DO NOT PROVIDE MORE ARGUMENTS THAN NECESSARY FOR THE NOTIFICATION YOU'RE CALLING! + The system is designed to save as much networking bandwidth as possible, + so please dynamically control your argument sending to fit *exactly* what is required. + 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(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(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(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"), "") \ + MULTITEAM_INFO(1, INFO_CTF_CAPTURE_BROKEN_, 2, 2, 2, "s1 f1p2dec s2 f2p2dec", "s1", "notify_%s_captured", _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds, breaking ^BG%s^BG's previous record of ^F2%s^BG seconds\n"), "") \ + MULTITEAM_INFO(1, INFO_CTF_CAPTURE_TIME_, 2, 1, 1, "s1 f1p2dec", "s1", "notify_%s_captured", _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds\n"), "") \ + MULTITEAM_INFO(1, INFO_CTF_CAPTURE_UNBROKEN_, 2, 2, 2, "s1 f1p2dec s2 f2p2dec", "s1", "notify_%s_captured", _("^BG%s^BG captured the ^TC^TT^BG flag in ^F2%s^BG seconds, failing to break ^BG%s^BG's previous record of ^F1%s^BG seconds\n"), "") \ + MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_ABORTRUN_, 2, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag was returned to base by its owner\n"), "") \ + MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_DAMAGED_, 2, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag was destroyed and returned to base\n"), "") \ + MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_DROPPED_, 2, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag was dropped in the base and returned itself\n"), "") \ + MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_NEEDKILL_, 2, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag fell somewhere it couldn't be reached and returned to base\n"), "") \ + MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_SPEEDRUN_, 2, 0, 1, "f1p2dec", "", "", _("^BGThe ^TC^TT^BG flag became impatient after ^F1%.2f^BG seconds and returned itself\n"), "") \ + MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_TIMEOUT_, 2, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag has returned to the base\n"), "") \ + MULTITEAM_INFO(1, INFO_CTF_LOST_, 2, 1, 0, "s1", "s1", "notify_%s_lost", _("^BG%s^BG lost the ^TC^TT^BG flag\n"), "") \ + MULTITEAM_INFO(1, INFO_CTF_PICKUP_, 2, 1, 0, "s1", "s1", "notify_%s_taken", _("^BG%s^BG got the ^TC^TT^BG flag\n"), "") \ + MULTITEAM_INFO(1, INFO_CTF_RETURN_, 2, 1, 0, "s1", "s1", "notify_%s_returned", _("^BG%s^BG returned the ^TC^TT^BG flag\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_CHEAT, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was unfairly eliminated by ^BG%s^K1%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_DROWN, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_water", _("^BG%s%s^K1 was drowned by ^BG%s^K1%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_FALL, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_fall", _("^BG%s%s^K1 was grounded by ^BG%s^K1%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_FIRE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was burnt up into a crisp by ^BG%s^K1%s%s\n"), _("^BG%s^K1 felt a little hot from ^BG%s^K1's fire^K1%s%s\n")) \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_LAVA, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_lava", _("^BG%s%s^K1 was cooked by ^BG%s^K1%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_SHOOTING_STAR, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_shootingstar", _("^BG%s%s^K1 was shot into space by ^BG%s^K1%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_SLIME, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_slime", _("^BG%s%s^K1 was slimed by ^BG%s^K1%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_SWAMP, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_slime", _("^BG%s%s^K1 was preserved by ^BG%s^K1%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_TELEFRAG, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_telefrag", _("^BG%s%s^K1 was telefragged by ^BG%s^K1%s%s\n"), _("^BG%s^K1 tried to occupy ^BG%s^K1's teleport destination space%s%s\n")) \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_TOUCHEXPLODE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 died in an accident with ^BG%s^K1%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_BUMB_DEATH, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Bumblebee exploded%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_BUMB_GUN, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 saw the pretty lights of ^BG%s^K1's Bumblebee gun%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_CRUSH, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was crushed by ^BG%s^K1%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_RAPT_BOMB, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was cluster bombed by ^BG%s^K1's Raptor%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_RAPT_CANNON, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 couldn't resist ^BG%s^K1's purple blobs%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_RAPT_DEATH, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Raptor exploded%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_SPID_DEATH, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Spiderbot exploded%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_SPID_MINIGUN, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 got shredded by ^BG%s^K1's Spiderbot%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_SPID_ROCKET, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was blasted to bits by ^BG%s^K1's Spiderbot%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_DEATH, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Racer exploded%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_GUN, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was bolted down by ^BG%s^K1's Racer%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_ROCKET, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 couldn't find shelter from ^BG%s^K1's Racer%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VOID, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_void", _("^BG%s%s^K1 was thrown into a world of hurt by ^BG%s^K1%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_AUTOTEAMCHANGE, 2, 1, "s1 s2loc death_team", "", "", _("^BG%s^K1 was moved into the %s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_BETRAYAL, 2, 1, "s1 s2loc spree_lost", "s1", "notify_teamkill_red", _("^BG%s^K1 became enemies with the Lord of Teamplay%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_CAMP, 2, 1, "s1 s2loc spree_lost", "s1", "notify_camping", _("^BG%s^K1 thought they found a nice camping ground%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_CHEAT, 2, 1, "s1 s2loc spree_lost", "s1", "notify_selfkill", _("^BG%s^K1 unfairly eliminated themself%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_CUSTOM, 3, 1, "s1 s2 s3loc spree_lost", "s1", "notify_void", _("^BG%s^K1 %s^K1%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_DROWN, 2, 1, "s1 s2loc spree_lost", "s1", "notify_water", _("^BG%s^K1 couldn't catch their breath%s%s\n"), _("^BG%s^K1 was in the water for too long%s%s\n")) \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_FALL, 2, 1, "s1 s2loc spree_lost", "s1", "notify_fall", _("^BG%s^K1 hit the ground with a crunch%s%s\n"), _("^BG%s^K1 hit the ground with a bit too much force%s%s\n")) \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_FIRE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 became a bit too crispy%s%s\n"), _("^BG%s^K1 felt a little hot%s%s\n")) \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_GENERIC, 2, 1, "s1 s2loc spree_lost", "s1", "notify_selfkill", _("^BG%s^K1 died%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_LAVA, 2, 1, "s1 s2loc spree_lost", "s1", "notify_lava", _("^BG%s^K1 turned into hot slag%s%s\n"), _("^BG%s^K1 found a hot place%s%s\n")) \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NOAMMO, 2, 1, "s1 s2loc spree_lost", "s1", "notify_outofammo", _("^BG%s^K1 died%s%s. What's the point of living without ammo?\n"), _("^BG%s^K1 ran out of ammo%s%s\n")) \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_ROT, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 rotted away%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_SHOOTING_STAR, 2, 1, "s1 s2loc spree_lost", "s1", "notify_shootingstar", _("^BG%s^K1 became a shooting star%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_SLIME, 2, 1, "s1 s2loc spree_lost", "s1", "notify_slime", _("^BG%s^K1 was slimed%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_SUICIDE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_selfkill", _("^BG%s^K1 couldn't take it anymore%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_SWAMP, 2, 1, "s1 s2loc spree_lost", "s1", "notify_slime", _("^BG%s^K1 is now preserved for centuries to come%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TEAMCHANGE, 2, 1, "s1 s2loc death_team", "", "", _("^BG%s^K1 switched to the %s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TOUCHEXPLODE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 died in an accident%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 ran into a turret%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_EWHEEL, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was blasted away by an eWheel turret%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_FLAC, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 got caught up in the FLAC turret fire%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_HELLION, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was blasted away by a Hellion turret%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_HK, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 could not hide from the Hunter turret%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_MACHINEGUN, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was riddled full of holes by a Machinegun turret%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_MLRS, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 got turned into smoldering gibs by an MLRS turret%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_PHASER, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was phased out by a turret%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_PLASMA, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 got served some superheated plasma from a turret%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_TESLA, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was electrocuted by a Tesla turret%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_WALK_GUN, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 got served a lead enrichment by a Walker turret%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_WALK_MEELE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was impaled by a Walker turret%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_WALK_ROCKET, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was blasted away by a Walker turret%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VH_BUMB_DEATH, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 got caught in the blast of a Bumblebee explosion%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VH_CRUSH, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was crushed by a vehicle%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VH_RAPT_BOMB, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was caught in a Raptor cluster bomb%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VH_RAPT_DEATH, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 got caught in the blast of a Raptor explosion%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VH_SPID_DEATH, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 got caught in the blast of a Spiderbot explosion%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VH_SPID_ROCKET, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was blasted to bits by a Spiderbot rocket%s%s\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%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_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(0, INFO_ITEM_WEAPON_DROP, 1, 1, "item_wepname item_wepammo", "", "", _("^BGYou dropped the ^F1%s^BG%s\n"), "") \ + MSG_INFO_NOTIF(0, INFO_ITEM_WEAPON_GOT, 0, 1, "item_wepname", "", "", _("^BGYou got the ^F1%s\n"), "") \ + MSG_INFO_NOTIF(0, INFO_ITEM_WEAPON_NOAMMO, 0, 1, "item_wepname", "", "", _("^BGYou don't have enough ammo for the ^F1%s\n"), "") \ + MSG_INFO_NOTIF(0, INFO_ITEM_WEAPON_PRIMORSEC, 0, 3, "item_wepname f2primsec f3primsec", "", "", _("^F1%s %s^BG is unable to fire, but its ^F1%s^BG can\n"), "") \ + MSG_INFO_NOTIF(0, INFO_ITEM_WEAPON_UNAVAILABLE, 0, 1, "item_wepname", "", "", _("^F1%s^BG is ^F4not available^BG on this map\n"), "") \ + MSG_INFO_NOTIF(2, INFO_JOIN_CONNECT, 1, 0, "s1", "", "", _("^BG%s^F3 connected%s\n"), "") \ + MULTITEAM_INFO(2, INFO_JOIN_CONNECT_TEAM_, 4, 1, 0, "s1", "", "", _("^BG%s^F3 connected and joined the ^TC^TT\n"), "") \ + MSG_INFO_NOTIF(1, INFO_JOIN_PLAY, 1, 0, "s1", "", "", _("^BG%s^F3 is now playing\n"), "") \ + MSG_INFO_NOTIF(1, INFO_KEEPAWAY_DROPPED, 1, 0, "s1", "s1", "notify_balldropped", _("^BG%s^BG has dropped the ball!\n"), "") \ + MSG_INFO_NOTIF(1, INFO_KEEPAWAY_PICKUP, 1, 0, "s1", "s1", "notify_ballpickedup", _("^BG%s^BG has picked up the ball!\n"), "") \ + MULTITEAM_INFO(1, INFO_KEYHUNT_CAPTURE_, 4, 1, 0, "s1", "", "", _("^BG%s^BG captured the keys for the ^TC^TT team\n"), "") \ + MULTITEAM_INFO(1, INFO_KEYHUNT_DROP_, 4, 1, 0, "s1", "", "", _("^BG%s^BG dropped the ^TC^TT Key\n"), "") \ + MULTITEAM_INFO(1, INFO_KEYHUNT_LOST_, 4, 1, 0, "s1", "", "", _("^BG%s^BG lost the ^TC^TT Key\n"), "") \ + MULTITEAM_INFO(1, INFO_KEYHUNT_PICKUP_, 4, 1, 0, "s1", "", "", _("^BG%s^BG picked up the ^TC^TT Key\n"), "") \ + MSG_INFO_NOTIF(1, INFO_LMS_FORFEIT, 1, 0, "s1", "", "", _("^BG%s^F3 forfeited\n"), "") \ + MSG_INFO_NOTIF(1, INFO_LMS_NOLIVES, 1, 0, "s1", "", "", _("^BG%s^F3 has no more lives left\n"), "") \ + MSG_INFO_NOTIF(1, INFO_POWERUP_INVISIBILITY, 1, 0, "s1", "s1", "strength", _("^BG%s^K1 picked up Invisibility\n"), "") \ + MSG_INFO_NOTIF(1, INFO_POWERUP_SHIELD, 1, 0, "s1", "s1", "shield", _("^BG%s^K1 picked up Shield\n"), "") \ + MSG_INFO_NOTIF(1, INFO_POWERUP_SPEED, 1, 0, "s1", "s1", "shield", _("^BG%s^K1 picked up Speed\n"), "") \ + MSG_INFO_NOTIF(1, INFO_POWERUP_STRENGTH, 1, 0, "s1", "s1", "strength", _("^BG%s^K1 picked up Strength\n"), "") \ + MSG_INFO_NOTIF(2, INFO_QUIT_DISCONNECT, 1, 0, "s1", "", "", _("^BG%s^F3 disconnected\n"), "") \ + MSG_INFO_NOTIF(2, INFO_QUIT_KICK_IDLING, 1, 0, "s1", "", "", _("^BG%s^F3 was kicked for idling\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 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_RACE_NEW_MISSING_UID, 1, 1, "s1 f1race_time", "s1", "race_newfail", _("^BG%s^BG scored a new record with ^F2%s^BG, but unfortunately lacks a UID and will be lost.\n"), "") \ + MSG_INFO_NOTIF(1, INFO_RACE_NEW_SET, 1, 2, "s1 race_col f1ord race_col f2race_time", "s1", "race_newrecordserver", _("^BG%s^BG set the %s%s^BG place record with %s%s\n"), "") \ + MULTITEAM_INFO(1, INFO_SCORES_, 4, 0, 0, "", "", "", _("^TC^TT ^BGteam scores!\n"), "") \ + MSG_INFO_NOTIF(1, INFO_SPECTATE_WARNING, 0, 1, "f1secs", "", "", _("^F2You have to become a player within the next %s, otherwise you will be kicked, because spectating isn't allowed at this time!\n"), "") \ + MSG_INFO_NOTIF(1, INFO_SUPERWEAPON_PICKUP, 1, 0, "s1", "s1", "strength", _("^BG%s^K1 picked up a Superweapon\n"), "") \ + MSG_INFO_NOTIF(2, INFO_VERSION_BETA, 2, 0, "s1 s2", "", "", _("^F4NOTE: ^BGThe server is running ^F1Xonotic %s (beta)^BG, you have ^F2Xonotic %s\n"), "") \ + MSG_INFO_NOTIF(2, INFO_VERSION_OLD, 2, 0, "s1 s2", "", "", _("^F4NOTE: ^BGThe server is running ^F1Xonotic %s^BG, you have ^F2Xonotic %s\n"), "") \ + MSG_INFO_NOTIF(2, INFO_VERSION_OUTDATED, 2, 0, "s1 s2", "", "", _("^F4NOTE: ^F1Xonotic %s^BG is out, and you still have ^F2Xonotic %s^BG - get the update from ^F3http://www.xonotic.org/^BG!\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WATERMARK, 1, 0, "s1", "", "", _("^F3SVQC Build information: ^F4%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_ACCORDEON_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weapontuba", _("^BG%s%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Accordeon%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_ACCORDEON_SUICIDE, 2, 1, "s1 s2loc spree_lost", "s1", "weapontuba", _("^BG%s^K1 hurt their own ears with the @!#%%'n Accordeon%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_CRYLINK_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponcrylink", _("^BG%s%s^K1 felt the strong pull of ^BG%s^K1's Crylink%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_CRYLINK_SUICIDE, 2, 1, "s1 s2loc spree_lost", "s1", "weaponcrylink", _("^BG%s^K1 felt the strong pull of their Crylink%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_ELECTRO_MURDER_BOLT, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponelectro", _("^BG%s%s^K1 was blasted by ^BG%s^K1's Electro bolt%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_ELECTRO_MURDER_COMBO, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponelectro", _("^BG%s%s^K1 felt the electrifying air of ^BG%s^K1's Electro combo%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_ELECTRO_MURDER_ORBS, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponelectro", _("^BG%s%s^K1 got too close to ^BG%s^K1's Electro plasma%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_ELECTRO_SUICIDE_BOLT, 2, 1, "s1 s2loc spree_lost", "s1", "weaponelectro", _("^BG%s^K1 played with Electro plasma%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_ELECTRO_SUICIDE_ORBS, 2, 1, "s1 s2loc spree_lost", "s1", "weaponelectro", _("^BG%s^K1 could not remember where they put their Electro plasma%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_FIREBALL_MURDER_BLAST, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponfireball", _("^BG%s%s^K1 got too close to ^BG%s^K1's fireball%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_FIREBALL_MURDER_FIREMINE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponfireball", _("^BG%s%s^K1 got burnt by ^BG%s^K1's firemine%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_FIREBALL_SUICIDE_BLAST, 2, 1, "s1 s2loc spree_lost", "s1", "weaponfireball", _("^BG%s^K1 should have used a smaller gun%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_FIREBALL_SUICIDE_FIREMINE, 2, 1, "s1 s2loc spree_lost", "s1", "weaponfireball", _("^BG%s^K1 forgot about their firemine%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_HAGAR_MURDER_BURST, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponhagar", _("^BG%s%s^K1 was pummeled by a burst of ^BG%s^K1's Hagar rockets%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_HAGAR_MURDER_SPRAY, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponhagar", _("^BG%s%s^K1 was pummeled by ^BG%s^K1's Hagar rockets%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_HAGAR_SUICIDE, 2, 1, "s1 s2loc spree_lost", "s1", "weaponhagar", _("^BG%s^K1 played with tiny Hagar rockets%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_HLAC_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponhlac", _("^BG%s%s^K1 was cut down with ^BG%s^K1's HLAC%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_HLAC_SUICIDE, 2, 1, "s1 s2loc spree_lost", "s1", "weaponhlac", _("^BG%s^K1 got a little jumpy with their HLAC%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_HOOK_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponhook", _("^BG%s%s^K1 was caught in ^BG%s^K1's Hook gravity bomb%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_KLEINBOTTLE_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weapontuba", _("^BG%s%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Klein Bottle%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_KLEINBOTTLE_SUICIDE, 2, 1, "s1 s2loc spree_lost", "s1", "weapontuba", _("^BG%s^K1 hurt their own ears with the @!#%%'n Klein Bottle%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_LASER_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponlaser", _("^BG%s%s^K1 was shot to death by ^BG%s^K1's Laser%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_LASER_SUICIDE, 2, 1, "s1 s2loc spree_lost", "s1", "weaponlaser", _("^BG%s^K1 shot themself to hell with their Laser%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_MINELAYER_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponminelayer", _("^BG%s%s^K1 got too close to ^BG%s^K1's mine%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_MINELAYER_SUICIDE, 2, 1, "s1 s2loc spree_lost", "s1", "weaponminelayer", _("^BG%s^K1 forgot about their mine%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_MINSTANEX_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponminstanex", _("^BG%s%s^K1 has been vaporized by ^BG%s^K1's Minstanex%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_MORTAR_MURDER_BOUNCE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weapongrenadelauncher", _("^BG%s%s^K1 got too close to ^BG%s^K1's Mortar grenade%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_MORTAR_MURDER_EXPLODE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weapongrenadelauncher", _("^BG%s%s^K1 ate ^BG%s^K1's Mortar grenade%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_MORTAR_SUICIDE_BOUNCE, 2, 1, "s1 s2loc spree_lost", "s1", "weapongrenadelauncher", _("^BG%s^K1 didn't see their own Mortar grenade%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_MORTAR_SUICIDE_EXPLODE, 2, 1, "s1 s2loc spree_lost", "s1", "weapongrenadelauncher", _("^BG%s^K1 blew themself up with their own Mortar%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_NEX_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponnex", _("^BG%s%s^K1 has been vaporized by ^BG%s^K1's Nex%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_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_ROCKETLAUNCHER_SUICIDE, 2, 1, "s1 s2loc spree_lost", "s1", "weaponrocketlauncher", _("^BG%s^K1 blew themself up with their Rocketlauncher%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_SEEKER_MURDER_SPRAY, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponseeker", _("^BG%s%s^K1 was pummeled by ^BG%s^K1's Seeker rockets%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_SEEKER_MURDER_TAG, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponseeker", _("^BG%s%s^K1 was tagged by ^BG%s^K1's Seeker%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_SEEKER_SUICIDE, 2, 1, "s1 s2loc spree_lost", "s1", "weaponseeker", _("^BG%s^K1 played with tiny Seeker rockets%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_SHOTGUN_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponshotgun", _("^BG%s%s^K1 was gunned down by ^BG%s^K1's Shotgun%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_SHOTGUN_MURDER_SLAP, 3, 2, "spree_inf s2 s1 s3loc spree_end", "s2 s1", "notify_melee_shotgun", _("^BG%s%s^K1 slapped ^BG%s^K1 around a bit with a large Shotgun%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_THINKING_WITH_PORTALS, 2, 1, "s1 s2loc spree_lost", "s1", "notify_selfkill", _("^BG%s^K1 is now thinking with portals%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_TUBA_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weapontuba", _("^BG%s%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Tuba%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_TUBA_SUICIDE, 2, 1, "s1 s2loc spree_lost", "s1", "weapontuba", _("^BG%s^K1 hurt their own ears with the @!#%%'n Tuba%s%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_WEAPON_UZI_MURDER_SNIPE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponuzi", _("^BG%s%s^K1 was sniped by ^BG%s^K1's Machine Gun%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(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(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(STATIC_NAME_TEAM_4)), TCR(gentle, COL_TEAM_4, strtoupper(STATIC_NAME_TEAM_4))) \ + #endif +#define MSG_CENTER_NOTIFICATIONS \ + 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_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_CTF_FLAG_THROW_PUNISH, 0, 1, "f1secs", CPID_CTF_LOWPRIO, "0 0", _("^BGToo many flag throws! Throwing disabled for %s."), "") \ + MULTITEAM_CENTER(1, CENTER_CTF_PASS_OTHER_, 2, 2, 0, "s1 s2", CPID_CTF_PASS, "0 0", _("^BG%s^BG passed the ^TC^TT^BG flag to %s"), "") \ + MULTITEAM_CENTER(1, CENTER_CTF_PASS_RECEIVED_, 2, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGYou received the ^TC^TT^BG flag from %s"), "") \ + MSG_CENTER_NOTIF(1, CENTER_CTF_PASS_REQUESTED, 1, 0, "s1 pass_key", CPID_CTF_PASS, "0 0", _("^BG%s^BG requests you to pass the flag%s"), "") \ + MSG_CENTER_NOTIF(1, CENTER_CTF_PASS_REQUESTING, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGRequesting %s^BG to pass you the flag"), "") \ + MULTITEAM_CENTER(1, CENTER_CTF_PASS_SENT_, 2, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGYou passed the ^TC^TT^BG flag to %s"), "") \ + MULTITEAM_CENTER(1, CENTER_CTF_PICKUP_, 2, 0, 0, "", CPID_CTF_LOWPRIO, "0 0", _("^BGYou got the ^TC^TT^BG flag!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_ENEMY, 1, 0, "s1", CPID_CTF_LOWPRIO, "0 0", _("^BGThe %senemy^BG got your flag! Retrieve it!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_ENEMY_VERBOSE, 2, 0, "s1 s2 s1", CPID_CTF_LOWPRIO, "0 0", _("^BGThe %senemy (^BG%s%s)^BG got your flag! Retrieve it!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_TEAM, 1, 0, "s1", CPID_CTF_LOWPRIO, "0 0", _("^BGYour %steam mate^BG got the flag! Protect them!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_TEAM_VERBOSE, 2, 0, "s1 s2 s1", CPID_CTF_LOWPRIO, "0 0", _("^BGYour %steam mate (^BG%s%s)^BG got the flag! Protect them!"), "") \ + MULTITEAM_CENTER(1, CENTER_CTF_RETURN_, 2, 0, 0, "", CPID_CTF_LOWPRIO, "0 0", _("^BGYou returned the ^TC^TT^BG flag!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_CTF_STALEMATE_CARRIER, 0, 0, "", CPID_STALEMATE, "0 0", _("^BGStalemate! Enemies can now see you on radar!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_CTF_STALEMATE_OTHER, 0, 0, "", CPID_STALEMATE, "0 0", _("^BGStalemate! Flag carriers can now be seen by enemies on radar!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_FRAG, 1, 1, "spree_cen s1", NO_CPID, "0 0", _("^K3%sYou fragged ^BG%s"), _("^K3%sYou scored against ^BG%s")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_FRAGGED, 1, 1, "spree_cen s1", NO_CPID, "0 0", _("^K1%sYou were fragged by ^BG%s"), _("^K1%sYou were scored against by ^BG%s")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_FRAGGED_VERBOSE, 1, 4, "spree_cen s1 frag_stats", NO_CPID, "0 0", _("^K1%sYou were fragged by ^BG%s^BG%s"), _("^K1%sYou were scored against by ^BG%s^BG%s")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_FRAG_VERBOSE, 1, 2, "spree_cen s1 frag_ping", NO_CPID, "0 0", _("^K3%sYou fragged ^BG%s^BG%s"), _("^K3%sYou scored against ^BG%s^BG%s")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAG, 1, 1, "spree_cen s1", NO_CPID, "0 0", _("^K1%sYou typefragged ^BG%s"), _("^K1%sYou scored against ^BG%s^K1 while they were typing")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAGGED, 1, 1, "spree_cen s1", NO_CPID, "0 0", _("^K1%sYou were typefragged by ^BG%s"), _("^K1%sYou were scored against by ^BG%s^K1 while typing!")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE, 1, 4, "spree_cen s1 frag_stats", NO_CPID, "0 0", _("^K1%sYou were typefragged by ^BG%s^BG%s"), _("^K1%sYou were scored against by ^BG%s^K1 while typing^BG%s")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE, 1, 2, "spree_cen s1 frag_ping", NO_CPID, "0 0", _("^K1%sYou typefragged ^BG%s^BG%s"), _("^K1%sYou scored against ^BG%s^K1 while they were typing^BG%s")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_AUTOTEAMCHANGE, 0, 1, "death_team", NO_CPID, "0 0", _("^BGYou have been moved into a different team\nYou are now on: %s"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_BETRAYAL, 0, 0, "", NO_CPID, "0 0", _("^K1Don't shoot your team mates!"), _("^K1Don't go against your team mates!")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_CAMP, 0, 0, "", NO_CPID, "0 0", _("^K1Die camper!"), _("^K1Reconsider your tactics, camper!")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_CHEAT, 0, 0, "", NO_CPID, "0 0", _("^K1You unfairly eliminated yourself!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_CUSTOM, 2, 0, "s2", NO_CPID, "0 0", _("^K1You were %s"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_DROWN, 0, 0, "", NO_CPID, "0 0", _("^K1You couldn't catch your breath!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_FALL, 0, 0, "", NO_CPID, "0 0", _("^K1You hit the ground with a crunch!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_FIRE, 0, 0, "", NO_CPID, "0 0", _("^K1You got a little bit too crispy!"), _("^K1You felt a little too hot!")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_GENERIC, 0, 0, "", NO_CPID, "0 0", _("^K1You killed your own dumb self!"), _("^K1You need to be more careful!")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_LAVA, 0, 0, "", NO_CPID, "0 0", _("^K1You couldn't stand the heat!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NOAMMO, 0, 0, "", NO_CPID, "0 0", _("^K1You were killed for running out of ammo..."), _("^K1You are respawning for running out of ammo...")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_ROT, 0, 0, "", NO_CPID, "0 0", _("^K1You grew too old without taking your medicine"), _("^K1You need to preserve your health")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_SHOOTING_STAR, 0, 0, "", NO_CPID, "0 0", _("^K1You became a shooting star!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_SLIME, 0, 0, "", NO_CPID, "0 0", _("^K1You melted away in slime!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_SUICIDE, 0, 0, "", NO_CPID, "0 0", _("^K1You committed suicide!"), _("^K1You ended it all!")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_SWAMP, 0, 0, "", NO_CPID, "0 0", _("^K1You got stuck in a swamp!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_TEAMCHANGE, 0, 1, "death_team", NO_CPID, "0 0", _("^BGYou are now on: %s"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_TOUCHEXPLODE, 0, 0, "", NO_CPID, "0 0", _("^K1You died in an accident!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_TURRET, 0, 0, "", NO_CPID, "0 0", _("^K1You were fragged by a turret!"), _("^K1You had an unfortunate run in with a turret!")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_TURRET_EWHEEL, 0, 0, "", NO_CPID, "0 0", _("^K1You were fragged by an eWheel turret!"), _("^K1You had an unfortunate run in with an eWheel turret!")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_TURRET_WALK, 0, 0, "", NO_CPID, "0 0", _("^K1You were fragged by a Walker turret!"), _("^K1You had an unfortunate run in with a Walker turret!")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_VH_BUMB_DEATH, 0, 0, "", NO_CPID, "0 0", _("^K1You got caught in the blast of a Bumblebee explosion!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_VH_CRUSH, 0, 0, "", NO_CPID, "0 0", _("^K1You were crushed by a vehicle!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_VH_RAPT_BOMB, 0, 0, "", NO_CPID, "0 0", _("^K1You were caught in a Raptor cluster bomb!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_VH_RAPT_DEATH, 0, 0, "", NO_CPID, "0 0", _("^K1You got caught in the blast of a Raptor explosion!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_VH_SPID_DEATH, 0, 0, "", NO_CPID, "0 0", _("^K1You got caught in the blast of a Spiderbot explosion!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_VH_SPID_ROCKET, 0, 0, "", NO_CPID, "0 0", _("^K1You were blasted to bits by a Spiderbot rocket!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_VH_WAKI_DEATH, 0, 0, "", NO_CPID, "0 0", _("^K1You got caught in the blast of a Racer explosion!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_VH_WAKI_ROCKET, 0, 0, "", NO_CPID, "0 0", _("^K1You couldn't find shelter from a Racer rocket!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_VOID, 0, 0, "", NO_CPID, "0 0", _("^K1Watch your step!"), "") \ + 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"), "") \ + 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", _("^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_ITEM_WEAPON_NOAMMO, 0, 1, "item_wepname", CPID_ITEM, "item_centime 0", _("^BGYou don't have enough ammo for the ^F1%s"), "") \ + MSG_CENTER_NOTIF(1, CENTER_ITEM_WEAPON_PRIMORSEC, 0, 3, "item_wepname f2primsec f3primsec", CPID_ITEM, "item_centime 0", _("^F1%s %s^BG is unable to fire, but its ^F1%s^BG can"), "") \ + MSG_CENTER_NOTIF(1, CENTER_ITEM_WEAPON_UNAVAILABLE, 0, 1, "item_wepname", CPID_ITEM, "item_centime 0", _("^F1%s^BG is ^F4not available^BG on this map"), "") \ + MSG_CENTER_NOTIF(1, CENTER_JOIN_NOSPAWNS, 0, 0, "", CPID_PREVENT_JOIN, "0 0", _("^K1No spawnpoints available!\nHope your team can fix it..."), "") \ + MSG_CENTER_NOTIF(1, CENTER_JOIN_PREVENT, 0, 0, "", CPID_PREVENT_JOIN, "0 0", _("^K1You may not join the game at this time.\nThe player limit reached maximum capacity."), "") \ + MSG_CENTER_NOTIF(1, CENTER_KEEPAWAY_DROPPED, 1, 0, "s1", CPID_KEEPAWAY, "0 0", _("^BG%s^BG has dropped the ball!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_KEEPAWAY_PICKUP, 1, 0, "s1", CPID_KEEPAWAY, "0 0", _("^BG%s^BG has picked up the ball!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_KEEPAWAY_WARN, 0, 0, "", CPID_KEEPAWAY_WARN, "0 0", _("^BGKilling people while you don't have the ball gives no points!"), "") \ + 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, "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_MOTD, 1, 0, "s1", CPID_MOTD, "-1 0", _("^BG%s"), "") \ + 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!\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_POWERDOWN_STRENGTH, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Strength has worn off"), "") \ + MSG_CENTER_NOTIF(1, CENTER_POWERUP_INVISIBILITY, 0, 0, "", CPID_POWERUP, "0 0", _("^F2You are invisible"), "") \ + MSG_CENTER_NOTIF(1, CENTER_POWERUP_SHIELD, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Shield surrounds you"), "") \ + MSG_CENTER_NOTIF(1, CENTER_POWERUP_SPEED, 0, 0, "", CPID_POWERUP, "0 0", _("^F2You are on speed"), "") \ + MSG_CENTER_NOTIF(1, CENTER_POWERUP_STRENGTH, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Strength infuses your weapons with devastating power"), "") \ + MSG_CENTER_NOTIF(1, CENTER_RACE_FINISHLAP, 0, 0, "", CPID_RACE_FINISHLAP, "0 0", _("^F2The race is over, finish your lap!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_SUPERWEAPON_BROKEN, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Superweapons have broken down"), "") \ + MSG_CENTER_NOTIF(1, CENTER_SUPERWEAPON_LOST, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Superweapons have been lost"), "") \ + MSG_CENTER_NOTIF(1, CENTER_SUPERWEAPON_PICKUP, 0, 0, "", CPID_POWERUP, "0 0", _("^F2You now have a superweapon"), "") \ + MULTITEAM_CENTER(1, CENTER_TEAMCHANGE_, 4, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Changing to ^TC^TT^K1 in ^COUNT"), "") \ + MSG_CENTER_NOTIF(1, CENTER_TEAMCHANGE_AUTO, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Changing team in ^COUNT"), "") \ + MSG_CENTER_NOTIF(1, CENTER_TEAMCHANGE_SPECTATE, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Spectating in ^COUNT"), "") \ + MSG_CENTER_NOTIF(1, CENTER_TEAMCHANGE_SUICIDE, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Suicide in ^COUNT"), "") \ + MSG_CENTER_NOTIF(1, CENTER_TIMEOUT_BEGINNING, 0, 1, "", CPID_TIMEOUT, "1 f1", _("^F4Timeout begins in ^COUNT"), "") \ + 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, 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) + + +// =========================== +// Special CVAR Declarations +// =========================== + +// MAKE SURE THIS IS ALWAYS SYNCHRONIZED WITH THE DUMP +// NOTIFICATIONS FUNCTION IN THE .QC FILE! + +#define NOTIF_ADD_AUTOCVAR(name,default) var float autocvar_notification_##name = default; + +var float autocvar_notification_show_location = FALSE; +var string autocvar_notification_show_location_string = ""; //_(" at the %s"); +var float autocvar_notification_show_sprees = TRUE; +var float autocvar_notification_show_sprees_info = 3; // 0 = off, 1 = target only, 2 = attacker only, 3 = target and attacker +var float autocvar_notification_show_sprees_info_newline = TRUE; +var float autocvar_notification_show_sprees_info_specialonly = TRUE; +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; +void Notification_GetCvars(void); +var float autocvar_notification_server_allows_frag_verbose = 1; // 0 = no, 1 = warmup only, 2 = all the time +var float autocvar_notification_server_allows_location = 1; // 0 = no, 1 = yes +#else +var float autocvar_notification_item_centerprinttime = 1.5; + +// 0 = no, 1 = yes, 2 = forced on for all MSG_INFO notifs +// DISABLED IN CODE, BUT ENABLED IN CONFIG FOR COMPATIBILITY WITH OLD CLIENTS +var float autocvar_notification_allow_chatboxprint = 0; + +var float autocvar_notification_show_sprees_center = TRUE; +var float autocvar_notification_show_sprees_center_specialonly = TRUE; +var float autocvar_notification_frag_verbose = TRUE; +#endif + + +// ============================ +// Notification Argument List +// ============================ +/* + These arguments get replaced with the Local_Notification_sprintf + and other such functions found in notifications.qc to supply data + from networked notifications to their usage in sprintf... It + allows for more dynamic data to be inferred by the local + notification parser, so that the server does not have to network + anything too crazy on a per-client/per-situation basis. + + Pay attention to the CSQC/SVQC relations, some of these are redefined + in slightly different ways for different programs, this is because the + server does a more conservative approach to the notifs than the client. + + All arguments are swapped into strings, so be sure that your + sprintf usage matches with proper %s placement. + + Argument descriptions: + s1-s4: string arguments to be literally swapped into sprintf + s2loc: s2 string of locations of deaths or other events + s3loc: s3 string of locations of deaths or other events + f1-f4: float arguments expanded into strings to be swapped into sprintf + f1p2dec: f1 float to string with 2 decimal places + f2p2dec: f2 float to string with 2 decimal places + f2primsec: f2 float primary or secondary selection for weapons + f3primsec: f3 float primary or secondary selection for weapons + f1secs: count_seconds of f1 + f1ord: count_ordinal of f1 + f1time: process_time of f1 + f1race_time: mmssss of f1 + 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 + 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 + frag_pos: show score status and position in the match of a player + spree_cen: centerprint notif for kill spree/how many kills they have + spree_inf: info notif for kill spree/how many kills they have + spree_end: placed at the end of murder messages to show ending of sprees + spree_lost: placed at the end of suicide messages to show losing of sprees + item_wepname: return full name of a weapon from weaponid + item_wepammo: ammo display for weapon from string + item_centime: amount of time to display weapon message in centerprint + death_team: show the full name of the team a player is switching from +*/ + +#define NOTIF_MAX_ARGS 7 +#define NOTIF_MAX_HUDARGS 2 +#define NOTIF_MAX_DURCNT 2 + +string arg_slot[NOTIF_MAX_ARGS]; + +#define ARG_CS_SV_HA 1 // enabled on CSQC, SVQC, and Hudargs +#define ARG_CS_SV_DC 2 // enabled on CSQC, SVQC, and durcnt centerprint +#define ARG_CS_SV 3 // enabled on CSQC and SVQC +#define ARG_CS 4 // unique result to CSQC +#define ARG_SV 5 // unique result to SVQC +#define ARG_DC 6 // unique result to durcnt/centerprint + +// todo possible idea.... declare how many floats/strings each arg needs, and then dynamically increment the input +// this way, we don't need to have duplicates like i.e. s2loc and s3loc? + +#define NOTIF_ARGUMENT_LIST \ + ARG_CASE(ARG_CS_SV_HA, "s1", s1) \ + ARG_CASE(ARG_CS_SV_HA, "s2", s2) \ + ARG_CASE(ARG_CS_SV_HA, "s3", s3) \ + ARG_CASE(ARG_CS_SV_HA, "s4", s4) \ + ARG_CASE(ARG_CS_SV, "s2loc", ((autocvar_notification_show_location && (s2 != "")) ? sprintf(( ((tmp_s = autocvar_notification_show_location_string) != "") ? tmp_s : _(" (near %s)") ), s2) : "")) \ + ARG_CASE(ARG_CS_SV, "s3loc", ((autocvar_notification_show_location && (s3 != "")) ? sprintf(( ((tmp_s = autocvar_notification_show_location_string) != "") ? tmp_s : _(" (near %s)") ), s3) : "")) \ + ARG_CASE(ARG_CS_SV_DC, "f1", ftos(f1)) \ + ARG_CASE(ARG_CS_SV_DC, "f2", ftos(f2)) \ + ARG_CASE(ARG_CS_SV, "f3", ftos(f3)) \ + ARG_CASE(ARG_CS_SV, "f4", ftos(f4)) \ + ARG_CASE(ARG_CS_SV, "f1p2dec", ftos_decimals(f1/100, 2)) \ + ARG_CASE(ARG_CS_SV, "f2p2dec", ftos_decimals(f2/100, 2)) \ + ARG_CASE(ARG_CS, "f2primsec", (f2 ? _("secondary") : _("primary"))) \ + ARG_CASE(ARG_CS, "f3primsec", (f3 ? _("secondary") : _("primary"))) \ + ARG_CASE(ARG_CS, "f1secs", count_seconds(f1)) \ + ARG_CASE(ARG_CS_SV, "f1ord", count_ordinal(f1)) \ + 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, "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)) \ + /*ARG_CASE(ARG_CS, "frag_pos", ((Should_Print_Score_Pos(f1)) ? sprintf("\n^BG%s", Read_Score_Pos(f1)) : ""))*/ \ + ARG_CASE(ARG_CS, "spree_cen", (autocvar_notification_show_sprees ? notif_arg_spree_cen(f1) : "")) \ + ARG_CASE(ARG_CS_SV, "spree_inf", (autocvar_notification_show_sprees ? notif_arg_spree_inf(1, input, s2, f2) : "")) \ + ARG_CASE(ARG_CS_SV, "spree_end", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-1, "", "", f1) : "")) \ + ARG_CASE(ARG_CS_SV, "spree_lost", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-2, "", "", f1) : "")) \ + ARG_CASE(ARG_CS_SV, "item_wepname", W_Name(f1)) \ + ARG_CASE(ARG_CS_SV, "item_wepammo", (s1 != "" ? sprintf(_(" with %s"), s1) : "")) \ + ARG_CASE(ARG_DC, "item_centime", ftos(autocvar_notification_item_centerprinttime)) \ + ARG_CASE(ARG_SV, "death_team", Team_ColoredFullName(f1)) \ + ARG_CASE(ARG_CS, "death_team", Team_ColoredFullName(f1 - 1)) + +#define NOTIF_HIT_MAX(count,funcname) if(sel_num == count) { backtrace(sprintf("%s: Hit maximum arguments!\n", funcname)); break; } +#define NOTIF_HIT_UNKNOWN(token,funcname) { backtrace(sprintf("%s: Hit unknown token in selected string! '%s'\n", funcname, selected)); break; } + +#define KILL_SPREE_LIST \ + SPREE_ITEM(3, 03, _("TRIPLE FRAG! "), _("%s^K1 made a TRIPLE FRAG! %s^BG"), _("%s^K1 made a TRIPLE SCORE! %s^BG")) \ + SPREE_ITEM(5, 05, _("RAGE! "), _("%s^K1 unlocked RAGE! %s^BG"), _("%s^K1 made FIVE SCORES IN A ROW! %s^BG")) \ + SPREE_ITEM(10, 10, _("MASSACRE! "), _("%s^K1 started a MASSACRE! %s^BG"), _("%s^K1 made TEN SCORES IN A ROW! %s^BG")) \ + SPREE_ITEM(15, 15, _("MAYHEM! "), _("%s^K1 executed MAYHEM! %s^BG"), _("%s^K1 made FIFTEEN SCORES IN A ROW! %s^BG")) \ + SPREE_ITEM(20, 20, _("BERSERKER! "), _("%s^K1 is a BERSERKER! %s^BG"), _("%s^K1 made TWENTY SCORES IN A ROW! %s^BG")) \ + SPREE_ITEM(25, 25, _("CARNAGE! "), _("%s^K1 inflicts CARNAGE! %s^BG"), _("%s^K1 made TWENTY FIVE SCORES IN A ROW! %s^BG")) \ + SPREE_ITEM(30, 30, _("ARMAGEDDON! "), _("%s^K1 unleashes ARMAGEDDON! %s^BG"), _("%s^K1 made THIRTY SCORES IN A ROW! %s^BG")) + +#ifdef CSQC +string notif_arg_frag_ping(float newline, float fping) +{ + if(fping == NO_MSG) + return sprintf(CCR(_("%s(^F1Bot^BG)")), (newline ? "\n" : " ")); + else + return sprintf(CCR(_("%s(Ping ^F1%d^BG)")), (newline ? "\n" : " "), fping); +} + +string notif_arg_frag_stats(float fhealth, float farmor, float fping) +{ + if not(fhealth < 1) + return sprintf(CCR(_("\n(Health ^1%d^BG / Armor ^2%d^BG)%s")), fhealth, farmor, notif_arg_frag_ping(FALSE, fping)); + else + return sprintf(CCR(_("\n(^F4Dead^BG)%s")), notif_arg_frag_ping(FALSE, fping)); +} + +string notif_arg_missing_teams(float f1, float f2, float f3, float f4) +{ + return sprintf("%s%s%s%s", + (f1 ? + sprintf("%s%s", Team_ColoredFullName(f1 - 1), ((f2 + f3 + f4) ? ", " : "")) + : + "" + ), + (f2 ? + sprintf("%s%s", Team_ColoredFullName(f2 - 1), ((f3 + f4) ? ", " : "")) + : + "" + ), + (f3 ? + sprintf("%s%s", Team_ColoredFullName(f3 - 1), (f4 ? ", " : "")) + : + "" + ), + (f4 ? + Team_ColoredFullName(f4 - 1) + : + "" + ) + ); +} + +string notif_arg_spree_cen(float spree) +{ + // 0 = off, 1 = target (but only for first victim) and attacker + if(autocvar_notification_show_sprees_center) + { + if(spree > 1) + { + #define SPREE_ITEM(counta,countb,center,normal,gentle) \ + case counta: { return normal_or_gentle(center, sprintf(_("%d score spree! "), spree)); } + + switch(spree) + { + KILL_SPREE_LIST + default: + { + if not(autocvar_notification_show_sprees_center_specialonly) + { + return + sprintf( + normal_or_gentle( + _("%d frag spree! "), + _("%d score spree! ") + ), + spree); + } + else { return ""; } // don't show spree information if it isn't an achievement + } + } + + #undef SPREE_ITEM + } + else if(spree == -1) // first blood + { + return normal_or_gentle(_("First blood! "), _("First score! ")); + } + else if(spree == -2) // first victim + { + return normal_or_gentle(_("First victim! "), _("First casualty! ")); + } + } + return ""; +} +#endif + +string notif_arg_spree_inf(float type, string input, string player, float spree) +{ + switch(type) + { + case 1: // attacker kill spree + { + // 0 = off, 1 = target only, 2 = attacker only, 3 = target and attacker + // this conditional (& 2) is true for 2 and 3 + if(autocvar_notification_show_sprees_info & 2) + { + #ifdef CSQC + string spree_newline = + ( autocvar_notification_show_sprees_info_newline ? + ((substring(input, 0, 1) == "\{3}") ? "\n\{3}" : "\n") : "" ); + #else + string spree_newline = + (autocvar_notification_show_sprees_info_newline ? "\n" : ""); + #endif + + if(spree > 1) + { + #define SPREE_ITEM(counta,countb,center,normal,gentle) \ + case counta: { return sprintf(CCR(normal_or_gentle(normal, gentle)), player, spree_newline); } + + switch(spree) + { + KILL_SPREE_LIST + default: + { + if not(autocvar_notification_show_sprees_info_specialonly) + { + return + sprintf( + CCR(normal_or_gentle( + _("%s^K1 has %d frags in a row! %s^BG"), + _("%s^K1 made %d scores in a row! %s^BG") + )), + player, + spree, + spree_newline + ); + } + else { return ""; } // don't show spree information if it isn't an achievement + } + } + + #undef SPREE_ITEM + } + else if(spree == -1) // firstblood + { + return + sprintf( + CCR(normal_or_gentle( + _("%s^K1 drew first blood! %s^BG"), + _("%s^K1 got the first score! %s^BG") + )), + player, + spree_newline + ); + } + } + break; + } + + case -1: // kill spree ended + { + if((spree > 1) && (autocvar_notification_show_sprees_info & 1)) + { + return + sprintf(normal_or_gentle( + _(", ending their %d frag spree"), + _(", ending their %d score spree") + ), + spree + ); + } + break; + } + + case -2: // kill spree lost + { + if((spree > 1) && (autocvar_notification_show_sprees_info & 1)) + { + return + sprintf(normal_or_gentle( + _(", losing their %d frag spree"), + _(", losing their %d score spree") + ), + spree + ); + } + break; + } + } + return ""; +} + + +// ==================================== +// Initialization/Create Declarations +// ==================================== + +#define NOTIF_FIRST 1 +#define NOTIF_MAX 1024 // limit of recursive functions with ACCUMULATE_FUNCTION + +// error detection +float notif_error; +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; +float NOTIF_CPID_COUNT; + +// notification entity values +.float nent_default; +.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_hudargs; +.string nent_icon; +.float nent_cpid; +.string nent_durcnt; +.string nent_string; + +// networked notification values +.float nent_broadcast; +.entity nent_client; +.float nent_net_type; +.float nent_net_name; +.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; \ + void RegisterNotification_##name() \ + { \ + SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_INFO_COUNT) \ + CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_INFO_COUNT, "notifications") \ + Create_Notification_Entity( \ + default, /* var_default */ \ + autocvar_notification_##name, /* var_cvar */ \ + 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 */ \ + hudargs, /* hudargs */ \ + icon, /* icon */ \ + NO_MSG, /* cpid */ \ + "", /* durcnt */ \ + normal, /* normal */ \ + gentle, /* gentle */ \ + TRUE, /* msg_is_info */ \ + FALSE); /* msg_is_multi */ \ + } \ + ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name) + +#define MSG_CENTER_NOTIF(default,name,strnum,flnum,args,cpid,durcnt,normal,gentle) \ + NOTIF_ADD_AUTOCVAR(name, default) \ + float name; \ + float cpid; \ + void RegisterNotification_##name() \ + { \ + SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_CENTER_COUNT) \ + SET_FIELD_COUNT(cpid, NOTIF_FIRST, NOTIF_CPID_COUNT) \ + CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_CENTER_COUNT, "notifications") \ + Create_Notification_Entity( \ + default, /* var_default */ \ + autocvar_notification_##name, /* var_cvar */ \ + 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 */ \ + "", /* hudargs */ \ + "", /* icon */ \ + cpid, /* cpid */ \ + durcnt, /* durcnt */ \ + normal, /* normal */ \ + gentle, /* gentle */ \ + FALSE, /* msg_is_info */ \ + FALSE); /* msg_is_multi */ \ + } \ + ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name) + +#define MSG_MULTI_NOTIF(default,name,anncename,infoname,centername) \ + NOTIF_ADD_AUTOCVAR(name, default) \ + float name; \ + void RegisterNotification_##name() \ + { \ + SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_MULTI_COUNT) \ + CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_MULTI_COUNT, "notifications") \ + Create_Notification_Entity( \ + default, /* var_default */ \ + autocvar_notification_##name, /* var_cvar */ \ + 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 */ \ + "", /* hudargs */ \ + "", /* icon */ \ + NO_MSG, /* cpid */ \ + "", /* durcnt */ \ + "", /* normal */ \ + "", /* gentle */ \ + FALSE, /* msg_is_info */ \ + TRUE); /* msg_is_multi */ \ + } \ + ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name) + +void RegisterNotifications_First() +{ + notif_global_error = FALSE; + + #ifdef SVQC + #define dedi (server_is_dedicated ? "a dedicated " : "") + #else + #define dedi "" + #endif + + print(sprintf("Beginning notification initialization on %s%s program...\n", dedi, PROGNAME)); + + // maybe do another implementation of this with checksums? for now, we don't need versioning + /*if(autocvar_notification_version != NOTIF_VERSION) + { + #ifdef CSQC + if(autocvar_notification_version_mismatch_client_error) + #else + if(autocvar_notification_version_mismatch_server_error) + #endif + notif_global_error = TRUE; + + print(sprintf("^1NOTIFICATION VERSION MISMATCH: ^7program = %s, config = %d, code = %d.\n", + PROGNAME, autocvar_notification_version, NOTIF_VERSION)); + }*/ +} + +void RegisterNotifications_Done() +{ + if(notif_global_error) + { + // shit happened... stop the loading of the program now if this is unacceptable + if(autocvar_notification_errors_are_fatal) + error("Notification initialization failed! Read above and fix the errors!\n"); + else + print("Notification initialization failed! Read above and fix the errors!\n"); + } + else { print("Notification initialization successful!\n"); } +} + +// 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 + +#undef NOTIF_ADD_AUTOCVAR diff --git a/qcsrc/common/teams.qh b/qcsrc/common/teams.qh new file mode 100644 index 0000000000..db3a39bcd5 --- /dev/null +++ b/qcsrc/common/teams.qh @@ -0,0 +1,162 @@ +#ifdef TEAMNUMBERS_THAT_ARENT_STUPID +const float NUM_TEAM_1 = 1; // red +const float NUM_TEAM_2 = 2; // blue +const float NUM_TEAM_3 = 3; // yellow +const float NUM_TEAM_4 = 4; // pink +const float NUM_SPECTATOR = 5; +#else +#ifdef CSQC +const float NUM_TEAM_1 = 4; // red +const float NUM_TEAM_2 = 13; // blue +const float NUM_TEAM_3 = 12; // yellow +const float NUM_TEAM_4 = 9; // pink +#else +const float NUM_TEAM_1 = 5; // red +const float NUM_TEAM_2 = 14; // blue +const float NUM_TEAM_3 = 13; // yellow +const float NUM_TEAM_4 = 10; // pink +#endif +const float NUM_SPECTATOR = 1337; +#endif + +const string COL_TEAM_1 = "^1"; +const string COL_TEAM_2 = "^4"; +const string COL_TEAM_3 = "^3"; +const string COL_TEAM_4 = "^6"; +const string NAME_TEAM_1 = _("Red"); +const string NAME_TEAM_2 = _("Blue"); +const string NAME_TEAM_3 = _("Yellow"); +const string NAME_TEAM_4 = _("Pink"); +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) +#define APP_TEAM_ENT_4(ent,prefix) ((ent.team == NUM_TEAM_1) ? prefix##RED : ((ent.team == NUM_TEAM_2) ? prefix##BLUE : ((ent.team == NUM_TEAM_3) ? prefix##YELLOW : prefix##PINK))) + +#ifdef CSQC +float teamplay; +float myteam; +#endif + +string Team_ColorCode(float teamid) +{ + switch(teamid) + { + case NUM_TEAM_1: return COL_TEAM_1; + case NUM_TEAM_2: return COL_TEAM_2; + case NUM_TEAM_3: return COL_TEAM_3; + case NUM_TEAM_4: return COL_TEAM_4; + } + + return "^7"; +} + +vector Team_ColorRGB(float teamid) +{ + switch(teamid) + { + 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'; + } + + return '0 0 0'; +} + +string Team_ColorName(float teamid) +{ + switch(teamid) + { + case NUM_TEAM_1: return NAME_TEAM_1; + case NUM_TEAM_2: return NAME_TEAM_2; + case NUM_TEAM_3: return NAME_TEAM_3; + case NUM_TEAM_4: return NAME_TEAM_4; + } + + 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)) + { + case "red": return NUM_TEAM_1; + case "blue": return NUM_TEAM_2; + case "yellow": return NUM_TEAM_3; + case "pink": return NUM_TEAM_4; + case "auto": return 0; + } + + return -1; +} + +float Team_NumberToTeam(float number) +{ + switch(number) + { + case 1: return NUM_TEAM_1; + case 2: return NUM_TEAM_2; + case 3: return NUM_TEAM_3; + case 4: return NUM_TEAM_4; + } + + return -1; +} + +float Team_TeamToNumber(float teamid) +{ + switch(teamid) + { + case NUM_TEAM_1: return 1; + case NUM_TEAM_2: return 2; + case NUM_TEAM_3: return 3; + case NUM_TEAM_4: return 4; + } + + return -1; +} + + +// legacy aliases for shitty code +#define TeamByColor(teamid) (Team_TeamToNumber(teamid) - 1) +#define ColorByTeam(number) Team_NumberToTeam(number + 1) + +// useful aliases +#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") + +#define Team_NumberToFullName(number) Team_FullName(Team_NumberToTeam(number)) +#define Team_NumberToColoredFullName(number) Team_ColoredFullName(Team_NumberToTeam(number)) + +// replace these flags in a string with the strings provided +#define TCR(input,teamcolor,teamtext) strreplace("^TC", teamcolor, strreplace("^TT", teamtext, input)) diff --git a/qcsrc/common/util-pre.qh b/qcsrc/common/util-pre.qh index dffce2f2bb..1c2c1cc9f2 100644 --- a/qcsrc/common/util-pre.qh +++ b/qcsrc/common/util-pre.qh @@ -9,7 +9,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 diff --git a/qcsrc/common/util.qc b/qcsrc/common/util.qc index 8f6a9c05c6..7fa2f576a6 100644 --- a/qcsrc/common/util.qc +++ b/qcsrc/common/util.qc @@ -2504,6 +2504,53 @@ void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t queue_start.FindConnectedComponent_processing = 0; } +// todo: this sucks, lets find a better way to do backtraces? +#ifndef MENUQC +void backtrace(string msg) +{ + float dev, war; + #ifdef SVQC + dev = autocvar_developer; + war = autocvar_prvm_backtraceforwarnings; + #else + dev = cvar("developer"); + war = cvar("prvm_backtraceforwarnings"); + #endif + cvar_set("developer", "1"); + cvar_set("prvm_backtraceforwarnings", "1"); + print("\n"); + print("--- CUT HERE ---\nWARNING: "); + print(msg); + print("\n"); + remove(world); // isn't there any better way to cause a backtrace? + print("\n--- CUT UNTIL HERE ---\n"); + cvar_set("developer", ftos(dev)); + cvar_set("prvm_backtraceforwarnings", ftos(war)); +} +#endif + +// color code replace, place inside of sprintf and parse the string +string CCR(string input) +{ + // See the autocvar declarations in util.qh for default values + + // foreground/normal colors + input = strreplace("^F1", strcat("^", autocvar_hud_colorset_foreground_1), input); + input = strreplace("^F2", strcat("^", autocvar_hud_colorset_foreground_2), input); + input = strreplace("^F3", strcat("^", autocvar_hud_colorset_foreground_3), input); + input = strreplace("^F4", strcat("^", autocvar_hud_colorset_foreground_4), input); + + // "kill" colors + input = strreplace("^K1", strcat("^", autocvar_hud_colorset_kill_1), input); + input = strreplace("^K2", strcat("^", autocvar_hud_colorset_kill_2), input); + input = strreplace("^K3", strcat("^", autocvar_hud_colorset_kill_3), input); + + // background colors + input = strreplace("^BG", strcat("^", autocvar_hud_colorset_background), input); + input = strreplace("^N", "^7", input); // "none"-- reset to white... + return input; +} + vector vec3(float x, float y, float z) { vector v; @@ -2532,3 +2579,30 @@ vector animfixfps(entity e, vector a, vector b) return a; } #endif + +#ifdef SVQC +void dedicated_print(string input) // print(), but only print if the server is not local +{ + 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 diff --git a/qcsrc/common/util.qh b/qcsrc/common/util.qh index 93a62fcf6d..e9bd01cfa4 100644 --- a/qcsrc/common/util.qh +++ b/qcsrc/common/util.qh @@ -37,6 +37,11 @@ void ACCUMULATE_call(string func) ACCUMULATE_call(#func) #endif +// used for simplifying ACCUMULATE_FUNCTIONs +#define SET_FIRST_OR_LAST(input,first,count) if(!input) { input = (first + count); } +#define SET_FIELD_COUNT(field,first,count) if(!field) { field = (first + count); ++count; } +#define CHECK_MAX_COUNT(name,max,count,type) if(count == max) { error(strcat("Maximum ", type, " hit: ", #name, ": ", ftos(count), ".\n")); } + // this returns a tempstring containing a copy of s with additional \n newlines added, it also replaces \n in the text with a real newline // NOTE: s IS allowed to be a tempstring string wordwrap(string s, float l); @@ -259,34 +264,6 @@ float get_model_parameters_fixbone; 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 @@ -353,8 +330,6 @@ void queue_to_execute_next_frame(string s); // for marking written-to values as unused where it's a good idea to do this noref float unused_float; - - // a function f with: // f(0) = 0 // f(1) = 1 @@ -371,8 +346,63 @@ typedef entity(entity cur, entity near, entity pass) findNextEntityNearFunction_ typedef float(entity a, entity b, entity pass) isConnectedFunction_t; void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t nxt, isConnectedFunction_t iscon, entity pass); +// expand multiple arguments into one argument by stripping parenthesis +#define XPD(...) __VA_ARGS__ + +#ifndef MENUQC +void backtrace(string msg); +#endif + +// color code replace, place inside of sprintf and parse the string... defaults described as constants +// foreground/normal colors +var string autocvar_hud_colorset_foreground_1 = "2"; // F1 - Green // primary priority (important names, etc) +var string autocvar_hud_colorset_foreground_2 = "3"; // F2 - Yellow // secondary priority (items, locations, numbers, etc) +var string autocvar_hud_colorset_foreground_3 = "4"; // F3 - Blue // tertiary priority or relatively inconsequential text +var string autocvar_hud_colorset_foreground_4 = "1"; // F4 - Red // notice/attention grabbing texting +// "kill" colors +var string autocvar_hud_colorset_kill_1 = "1"; // K1 - Red // "bad" or "dangerous" text (death messages against you, kill notifications, etc) +var string autocvar_hud_colorset_kill_2 = "3"; // K2 - Yellow // similar to above, but less important... OR, a highlight out of above message type +var string autocvar_hud_colorset_kill_3 = "4"; // K3 - Blue // "good" or "beneficial" text (you fragging someone, etc) +// background color +var string autocvar_hud_colorset_background = "7"; // BG - White // neutral/unimportant text + +string CCR(string input); + +#ifndef MENUQC +#ifdef CSQC +#define GENTLE (autocvar_cl_gentle || autocvar_cl_gentle_messages) +#else +#define GENTLE autocvar_sv_gentle +#endif +#define normal_or_gentle(normal,gentle) (GENTLE ? ((gentle != "") ? gentle : normal) : normal) +#endif + +// allow writing to also pass through to spectators (like so spectators see the same centerprints as players for example) +#define WRITESPECTATABLE_MSG_ONE_VARNAME(varname,statement) entity varname; varname = msg_entity; FOR_EACH_REALCLIENT(msg_entity) if(msg_entity == varname || (msg_entity.classname == STR_SPECTATOR && msg_entity.enemy == varname)) statement msg_entity = varname +#define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement) +#define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0 + vector vec3(float x, float y, float z); #ifndef MENUQC vector animfixfps(entity e, vector a, vector b); #endif + +#ifdef SVQC +void dedicated_print(string input); +#endif + +// todo: better way to do this? +#ifdef MENUQC +#define PROGNAME "MENUQC" +#else +#ifdef SVQC +#define PROGNAME "SVQC" +#else +#define PROGNAME "CSQC" +#endif +#endif + +#ifndef MENUQC +float Announcer_PickNumber(float num); +#endif diff --git a/qcsrc/menu/classes.c b/qcsrc/menu/classes.c index 0a3a55c5f1..f00971674e 100644 --- a/qcsrc/menu/classes.c +++ b/qcsrc/menu/classes.c @@ -43,6 +43,7 @@ #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" diff --git a/qcsrc/menu/item/inputbox.c b/qcsrc/menu/item/inputbox.c index 572d3a0710..614f6d5576 100644 --- a/qcsrc/menu/item/inputbox.c +++ b/qcsrc/menu/item/inputbox.c @@ -5,10 +5,12 @@ CLASS(InputBox) EXTENDS(Label) 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) @@ -26,6 +28,15 @@ CLASS(InputBox) EXTENDS(Label) 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 @@ -37,6 +48,16 @@ void InputBox_configureInputBox(entity me, string theText, float theCursorPos, f 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) { @@ -50,18 +71,60 @@ void InputBox_Clear_Click(entity btn, entity me) 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); @@ -69,8 +132,19 @@ float InputBox_mousePress(entity me, vector 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) @@ -295,6 +369,17 @@ void InputBox_draw(entity me) 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); } diff --git a/qcsrc/menu/item/inputcontainer.c b/qcsrc/menu/item/inputcontainer.c index 65129b294d..4531a1f4e1 100644 --- a/qcsrc/menu/item/inputcontainer.c +++ b/qcsrc/menu/item/inputcontainer.c @@ -134,6 +134,8 @@ float InputContainer_mouseDrag(entity me, vector pos) } 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; diff --git a/qcsrc/menu/item/nexposee.c b/qcsrc/menu/item/nexposee.c index 64da6bcd6d..97eabd7d66 100644 --- a/qcsrc/menu/item/nexposee.c +++ b/qcsrc/menu/item/nexposee.c @@ -263,7 +263,7 @@ float Nexposee_mouseMove(entity me, vector pos) 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; } diff --git a/qcsrc/menu/menu.qc b/qcsrc/menu/menu.qc index ddf9ff686a..2dc73a8d22 100644 --- a/qcsrc/menu/menu.qc +++ b/qcsrc/menu/menu.qc @@ -687,7 +687,7 @@ void m_draw() 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! diff --git a/qcsrc/menu/progs.src b/qcsrc/menu/progs.src index e45a4813a6..36905e17ad 100644 --- a/qcsrc/menu/progs.src +++ b/qcsrc/menu/progs.src @@ -13,10 +13,12 @@ config.qh oo/base.h +../common/teams.qh ../common/constants.qh ../common/mapinfo.qh ../common/campaign_common.qh ../common/items.qh +../common/counting.qh ../common/command/markup.qh ../common/command/rpn.qh ../common/command/generic.qh diff --git a/qcsrc/menu/skin-customizables.inc b/qcsrc/menu/skin-customizables.inc index d30ac7248d..6b5cac042c 100644 --- a/qcsrc/menu/skin-customizables.inc +++ b/qcsrc/menu/skin-customizables.inc @@ -166,6 +166,13 @@ SKINBEGIN 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); diff --git a/qcsrc/menu/xonotic/charmap.c b/qcsrc/menu/xonotic/charmap.c index 0e375c9cc4..6966aaf481 100644 --- a/qcsrc/menu/xonotic/charmap.c +++ b/qcsrc/menu/xonotic/charmap.c @@ -64,7 +64,7 @@ float XonoticCharmap_mouseMove(entity me, vector coords) 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; } diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create.c b/qcsrc/menu/xonotic/dialog_multiplayer_create.c index a534016931..3fc6f31fe3 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_create.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_create.c @@ -153,7 +153,6 @@ void XonoticServerCreateTab_gameTypeChangeNotify(entity me) case MAPINFO_TYPE_CTF: GameType_ConfigureSliders(e, l, l2, _("Capture limit:"), 1, 20, 1, "capturelimit_override"); break; case MAPINFO_TYPE_DOMINATION: GameType_ConfigureSliders(e, l, l2, _("Point limit:"), 50, 500, 10, "g_domination_point_limit"); break; case MAPINFO_TYPE_KEYHUNT: GameType_ConfigureSliders(e, l, l2, _("Point limit:"), 200, 1500, 50, "g_keyhunt_point_limit"); break; - case MAPINFO_TYPE_RUNEMATCH: GameType_ConfigureSliders(e, l, l2, _("Point limit:"), 50, 500, 10, "g_runematch_point_limit"); break; case MAPINFO_TYPE_LMS: GameType_ConfigureSliders(e, l, l2, _("Lives:"), 3, 50, 1, "g_lms_lives_override"); break; case MAPINFO_TYPE_RACE: GameType_ConfigureSliders(e, l, l2, _("Laps:"), 1, 25, 1, "g_race_laps_limit"); break; case MAPINFO_TYPE_NEXBALL: GameType_ConfigureSliders(e, l, l2, _("Goals:"), 1, 50, 1, "g_nexball_goallimit"); break; diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create_advanced.c b/qcsrc/menu/xonotic/dialog_multiplayer_create_advanced.c index 3fcabaaab6..e6fffe0936 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_create_advanced.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_create_advanced.c @@ -55,7 +55,7 @@ void XonoticAdvancedDialog_fill(entity me) 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"); diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c b/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c index e4128235f2..40fb4cca5e 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c @@ -102,65 +102,14 @@ string XonoticMutatorsDialog_toString(entity me) 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")) @@ -187,17 +136,33 @@ float checkCompatibility_newtoys(entity me) 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"))); @@ -254,10 +219,11 @@ void XonoticMutatorsDialog_fill(entity me) 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); @@ -265,47 +231,38 @@ void XonoticMutatorsDialog_fill(entity me) 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')); diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_demo.c b/qcsrc/menu/xonotic/dialog_multiplayer_demo.c index bb4b969c4c..84115f1ed6 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_demo.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_demo.c @@ -20,22 +20,17 @@ entity makeXonoticDemoBrowserTab() } 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); diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_join.c b/qcsrc/menu/xonotic/dialog_multiplayer_join.c index ee451744fb..02d3b41020 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_join.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_join.c @@ -20,18 +20,15 @@ entity makeXonoticServerListTab() } 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; diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup.c b/qcsrc/menu/xonotic/dialog_multiplayer_playersetup.c index ef930b4e14..21beeca6f4 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_playersetup.c @@ -45,6 +45,7 @@ void XonoticPlayerSettingsTab_fill(entity me) 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)); diff --git a/qcsrc/menu/xonotic/dialog_settings_misc.c b/qcsrc/menu/xonotic/dialog_settings_misc.c index b9aab55ab7..37effe9325 100644 --- a/qcsrc/menu/xonotic/dialog_settings_misc.c +++ b/qcsrc/menu/xonotic/dialog_settings_misc.c @@ -49,6 +49,7 @@ void XonoticMiscSettingsTab_fill(entity me) 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); diff --git a/qcsrc/menu/xonotic/dialog_settings_misc_cvars.c b/qcsrc/menu/xonotic/dialog_settings_misc_cvars.c index 7ebca4162c..5db6d35c62 100644 --- a/qcsrc/menu/xonotic/dialog_settings_misc_cvars.c +++ b/qcsrc/menu/xonotic/dialog_settings_misc_cvars.c @@ -17,26 +17,27 @@ void XonoticCvarsDialog_showNotify(entity me) } 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); @@ -54,6 +55,9 @@ void XonoticCvarsDialog_fill(entity me) // in this dialog, use SKINCOLOR_CVARLIS 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; diff --git a/qcsrc/menu/xonotic/inputbox.c b/qcsrc/menu/xonotic/inputbox.c index dbbcc7b0c4..56aa9702c6 100644 --- a/qcsrc/menu/xonotic/inputbox.c +++ b/qcsrc/menu/xonotic/inputbox.c @@ -16,6 +16,13 @@ CLASS(XonoticInputBox) EXTENDS(InputBox) 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)) diff --git a/qcsrc/menu/xonotic/radiobutton.c b/qcsrc/menu/xonotic/radiobutton.c index 8c353eae67..4ac5aa7b18 100644 --- a/qcsrc/menu/xonotic/radiobutton.c +++ b/qcsrc/menu/xonotic/radiobutton.c @@ -13,6 +13,7 @@ CLASS(XonoticRadioButton) EXTENDS(RadioButton) 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)) @@ -98,7 +99,12 @@ void XonoticRadioButton_saveCvars(entity me) 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); } diff --git a/qcsrc/menu/xonotic/util.qc b/qcsrc/menu/xonotic/util.qc index e80bf30e4e..b4ca21385d 100644 --- a/qcsrc/menu/xonotic/util.qc +++ b/qcsrc/menu/xonotic/util.qc @@ -609,7 +609,6 @@ float updateCompression() GAMETYPE(MAPINFO_TYPE_ONSLAUGHT) \ GAMETYPE(MAPINFO_TYPE_RACE) \ GAMETYPE(MAPINFO_TYPE_CTS) \ - GAMETYPE(MAPINFO_TYPE_RUNEMATCH) \ GAMETYPE(MAPINFO_TYPE_TEAM_DEATHMATCH) \ /* nothing */ diff --git a/qcsrc/menu/xonotic/weaponarenacheckbox.c b/qcsrc/menu/xonotic/weaponarenacheckbox.c new file mode 100644 index 0000000000..163f9c63b4 --- /dev/null +++ b/qcsrc/menu/xonotic/weaponarenacheckbox.c @@ -0,0 +1,57 @@ +#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 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) - { - FOR_EACH_REALCLIENT(e) - Send_CSQC_Centerprint_Generic_Expire(e, CPID_ROUND_STARTING); - 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)) { - FOR_EACH_REALCLIENT(self) - Send_CSQC_Centerprint_Generic(self, CPID_ROUND_STARTING, "^1Need at least 1 player in each team to play CA", 2, 0); - 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"); - - FOR_EACH_REALCLIENT(e) - Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "Round will start in %d", 1, 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"); - FOR_EACH_REALCLIENT(e) - Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "^1Begin!", 1, 0); - } - - 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 == COLOR_TEAM1) - { - red_players += 1; - total_players += 1; - } - else if (self.team == COLOR_TEAM2) - { - blue_players += 1; - total_players += 1; - } - else if (self.team == COLOR_TEAM3) - { - yellow_players += 1; - total_players += 1; - } - else if (self.team == COLOR_TEAM4) - { - 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 == COLOR_TEAM1 && self.health >= 1) - { - redalive += 1; - totalalive += 1; - } - else if (self.team == COLOR_TEAM2 && 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 == COLOR_TEAM1 && self.freezetag_frozen == 0 && self.health >= 1) - { - redalive += 1; - totalalive += 1; - } - else if (self.team == COLOR_TEAM2 && self.freezetag_frozen == 0 && self.health >= 1) - { - bluealive += 1; - totalalive += 1; - } - else if (self.team == COLOR_TEAM3 && self.freezetag_frozen == 0 && self.health >= 1) - { - yellowalive += 1; - totalalive += 1; - } - else if (self.team == COLOR_TEAM4 && 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(COLOR_TEAM1, ST_SCORE, +1); - } - else if(bluealive) { - play2all("ctf/blue_capture.wav"); - FOR_EACH_CLIENT(self) centerprint(self, "^4BLUE ^7team wins the round"); - TeamScore_AddToTeam(COLOR_TEAM2, 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(); - } - } - } -} diff --git a/qcsrc/server/assault.qc b/qcsrc/server/assault.qc deleted file mode 100644 index 2562dca3df..0000000000 --- a/qcsrc/server/assault.qc +++ /dev/null @@ -1,376 +0,0 @@ -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 = COLOR_TEAM1; // red, gets swapped every round - spawnfunc_info_player_deathmatch(); -} - -void spawnfunc_info_player_defender() { - if(!g_assault) - { - remove(self); - return; - } - self.team = COLOR_TEAM2; // 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("", 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 == COLOR_TEAM1) { - self.team = COLOR_TEAM2; - } else { - self.team = COLOR_TEAM1; - } - 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 == COLOR_TEAM1) - ent.team = COLOR_TEAM2; - else - ent.team = COLOR_TEAM1; - - 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 = COLOR_TEAM1; - 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 == COLOR_TEAM1) { - assault_attacker_team = COLOR_TEAM2; - } else { - assault_attacker_team = COLOR_TEAM1; - } - - - entity ent; - for(ent = world; (ent = nextent(ent)); ) - { - if(clienttype(ent) == CLIENTTYPE_NOTACLIENT) - { - if(ent.team_saved == COLOR_TEAM1) - ent.team_saved = COLOR_TEAM2; - else if(ent.team_saved == COLOR_TEAM2) - ent.team_saved = COLOR_TEAM1; - } - } - - // reset the level with a countdown - cvar_set("timelimit", ftos(ceil(time - game_starttime) / 60)); - ReadyRestart_force(); // sets game_starttime -} diff --git a/qcsrc/server/attic/assault.qc b/qcsrc/server/attic/assault.qc new file mode 100644 index 0000000000..7a5662c979 --- /dev/null +++ b/qcsrc/server/attic/assault.qc @@ -0,0 +1,376 @@ +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("", 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 +} diff --git a/qcsrc/server/attic/bot/havocbot/role_assault.qc b/qcsrc/server/attic/bot/havocbot/role_assault.qc new file mode 100644 index 0000000000..4456802d5c --- /dev/null +++ b/qcsrc/server/attic/bot/havocbot/role_assault.qc @@ -0,0 +1,205 @@ +#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 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); +} diff --git a/qcsrc/server/attic/ctf.qc b/qcsrc/server/attic/ctf.qc index d65d866ca6..b86e843699 100644 --- a/qcsrc/server/attic/ctf.qc +++ b/qcsrc/server/attic/ctf.qc @@ -127,10 +127,10 @@ void ctf_flag_spawnstuff() self.nearestwaypointtimeout = 0; // activate waypointing again self.basewaypoint = self.nearestwaypoint; - if(self.team == COLOR_TEAM1) - WaypointSprite_SpawnFixed("redbase", self.origin + '0 0 61', self, sprite, RADARICON_FLAG, colormapPaletteColor(COLOR_TEAM1 - 1, FALSE)); + if(self.team == NUM_TEAM_1) + WaypointSprite_SpawnFixed("redbase", self.origin + '0 0 61', self, sprite, RADARICON_FLAG, colormapPaletteColor(NUM_TEAM_1 - 1, FALSE)); else - WaypointSprite_SpawnFixed("bluebase", self.origin + '0 0 61', self, sprite, RADARICON_FLAG, colormapPaletteColor(COLOR_TEAM2 - 1, FALSE)); + WaypointSprite_SpawnFixed("bluebase", self.origin + '0 0 61', self, sprite, RADARICON_FLAG, colormapPaletteColor(NUM_TEAM_2 - 1, FALSE)); } float ctf_score_value(string parameter) @@ -290,7 +290,7 @@ void DropFlag(entity e, entity penalty_receiver, entity attacker) ctf_captureshield_update(p, 0); // shield only e.playerid = attacker.playerid; e.ctf_droptime = time; - WaypointSprite_Spawn("flagdropped", 0, 0, e, '0 0 1' * 61, world, COLOR_TEAM1 + COLOR_TEAM2 - e.team, e, waypointsprite_attachedforcarrier, FALSE, RADARICON_FLAG, '0 1 1'); + WaypointSprite_Spawn("flagdropped", 0, 0, e, '0 0 1' * 61, world, NUM_TEAM_1 + NUM_TEAM_2 - e.team, e, waypointsprite_attachedforcarrier, FALSE, RADARICON_FLAG, '0 1 1'); WaypointSprite_Ping(e.waypointsprite_attachedforcarrier); if(p.waypointsprite_attachedforcarrier) @@ -494,11 +494,11 @@ void FlagTouch() UpdateFrags(other, ctf_score_value("score_capture")); if (autocvar_g_ctf_flag_capture_effects) { - if (other.team == COLOR_TEAM1) { // red team scores effect + if (other.team == NUM_TEAM_1) { // red team scores effect pointparticles(particleeffectnum("red_ground_quake"), self.origin, '0 0 0', 1); flag_cap_ring_spawn(self.origin); } - if (other.team == COLOR_TEAM2) { // blue team scores effect + if (other.team == NUM_TEAM_2) { // blue team scores effect pointparticles(particleeffectnum("blue_ground_quake"), self.origin, '0 0 0', 1); flag_cap_ring_spawn(self.origin); } @@ -513,7 +513,7 @@ void FlagTouch() other.next_take_time = time + 1; } if (self.cnt == FLAG_BASE) - if (other.team == COLOR_TEAM1 || other.team == COLOR_TEAM2) // only red and blue team can steal flags + if (other.team == NUM_TEAM_1 || other.team == NUM_TEAM_2) // only red and blue team can steal flags if (other.team != self.team) if (!other.flagcarried) if (!other.ctf_captureshielded) @@ -563,7 +563,7 @@ void FlagTouch() if (self.cnt == FLAG_DROPPED) { self.flags = FL_ITEM | FL_NOTARGET; // clear FL_ONGROUND and any other junk - if (other.team == self.team || (other.team != COLOR_TEAM1 && other.team != COLOR_TEAM2)) + if (other.team == self.team || (other.team != NUM_TEAM_1 && other.team != NUM_TEAM_2)) { // return flag Send_KillNotification (other.netname, self.netname, "", INFO_RETURNFLAG, MSG_INFO); @@ -578,22 +578,22 @@ void FlagTouch() } // punish the team who was last carrying it - if(self.team == COLOR_TEAM1) - TeamScore_AddToTeam(COLOR_TEAM2, ST_SCORE, -ctf_score_value("penalty_returned")); + if(self.team == NUM_TEAM_1) + TeamScore_AddToTeam(NUM_TEAM_2, ST_SCORE, -ctf_score_value("penalty_returned")); else - TeamScore_AddToTeam(COLOR_TEAM1, ST_SCORE, -ctf_score_value("penalty_returned")); + TeamScore_AddToTeam(NUM_TEAM_1, ST_SCORE, -ctf_score_value("penalty_returned")); // reward the player who returned it if(other.playerid == self.playerid) // is this the guy who killed the FC last? { - if (other.team == COLOR_TEAM1 || other.team == COLOR_TEAM2) + if (other.team == NUM_TEAM_1 || other.team == NUM_TEAM_2) UpdateFrags(other, ctf_score_value("score_return_by_killer")); else UpdateFrags(other, ctf_score_value("score_return_rogue_by_killer")); } else { - if (other.team == COLOR_TEAM1 || other.team == COLOR_TEAM2) + if (other.team == NUM_TEAM_1 || other.team == NUM_TEAM_2) UpdateFrags(other, ctf_score_value("score_return")); else UpdateFrags(other, ctf_score_value("score_return_rogue")); @@ -663,7 +663,7 @@ void spawnfunc_info_player_team1() remove(self); return; } - self.team = COLOR_TEAM1; // red + self.team = NUM_TEAM_1; // red spawnfunc_info_player_deathmatch(); } //self.team = 4;self.classname = "info_player_start";spawnfunc_info_player_start();} @@ -683,7 +683,7 @@ void spawnfunc_info_player_team2() remove(self); return; } - self.team = COLOR_TEAM2; // blue + self.team = NUM_TEAM_2; // blue spawnfunc_info_player_deathmatch(); } //self.team = 13;self.classname = "info_player_start";spawnfunc_info_player_start();} @@ -703,7 +703,7 @@ void spawnfunc_info_player_team3() remove(self); return; } - self.team = COLOR_TEAM3; // yellow + self.team = NUM_TEAM_3; // yellow spawnfunc_info_player_deathmatch(); } @@ -723,7 +723,7 @@ void spawnfunc_info_player_team4() remove(self); return; } - self.team = COLOR_TEAM4; // purple + self.team = NUM_TEAM_4; // purple spawnfunc_info_player_deathmatch(); } @@ -741,11 +741,11 @@ void item_flag_postspawn() // Flag Glow Trail Support if(autocvar_g_ctf_flag_glowtrails) { // Provide Flag Glow Trail - if(self.team == COLOR_TEAM1) + if(self.team == NUM_TEAM_1) // Red self.glow_color = 251; else - if(self.team == COLOR_TEAM2) + if(self.team == NUM_TEAM_2) // Blue self.glow_color = 210; @@ -802,7 +802,7 @@ void spawnfunc_item_flag_team1() ctf_worldflaglist = self; self.classname = "item_flag_team"; - self.team = COLOR_TEAM1; // color 4 team (red) + self.team = NUM_TEAM_1; // color 4 team (red) self.items = IT_KEY2; // gold key (redish enough) self.netname = "^1RED^7 flag"; self.target = "###item###"; @@ -901,7 +901,7 @@ void spawnfunc_item_flag_team2() ctf_worldflaglist = self; self.classname = "item_flag_team"; - self.team = COLOR_TEAM2; // color 13 team (blue) + self.team = NUM_TEAM_2; // color 13 team (blue) self.items = IT_KEY1; // silver key (bluish enough) self.netname = "^4BLUE^7 flag"; self.target = "###item###"; @@ -1002,8 +1002,8 @@ void ctf_spawnteams() numteams = 2;//cvar("g_ctf_default_teams"); - ctf_spawnteam("Red", COLOR_TEAM1 - 1); - ctf_spawnteam("Blue", COLOR_TEAM2 - 1); + ctf_spawnteam("Red", NUM_TEAM_1 - 1); + ctf_spawnteam("Blue", NUM_TEAM_2 - 1); } void ctf_delayedinit() @@ -1089,7 +1089,7 @@ void ctf_setstatus() entity ctf_team_has_commander(float cteam) { entity pl; - if(cteam != COLOR_TEAM1 || cteam != COLOR_TEAM2) + if(cteam != NUM_TEAM_1 || cteam != NUM_TEAM_2) return world; FOR_EACH_REALPLAYER(pl) { diff --git a/qcsrc/server/attic/domination.qc b/qcsrc/server/attic/domination.qc index 6a0dcdf8b4..a898b53e99 100644 --- a/qcsrc/server/attic/domination.qc +++ b/qcsrc/server/attic/domination.qc @@ -131,16 +131,16 @@ void dompoint_captured () switch(self.goalentity.team) { - case COLOR_TEAM1: + case NUM_TEAM_1: WaypointSprite_UpdateSprites(self.sprite, "dom-red", "", ""); break; - case COLOR_TEAM2: + case NUM_TEAM_2: WaypointSprite_UpdateSprites(self.sprite, "dom-blue", "", ""); break; - case COLOR_TEAM3: + case NUM_TEAM_3: WaypointSprite_UpdateSprites(self.sprite, "dom-yellow", "", ""); break; - case COLOR_TEAM4: + case NUM_TEAM_4: WaypointSprite_UpdateSprites(self.sprite, "dom-pink", "", ""); } @@ -157,16 +157,16 @@ void dompoint_captured () wait_time = head.wait; switch(head.goalentity.team) { - case COLOR_TEAM1: + case NUM_TEAM_1: pps_red += points/wait_time; break; - case COLOR_TEAM2: + case NUM_TEAM_2: pps_blue += points/wait_time; break; - case COLOR_TEAM3: + case NUM_TEAM_3: pps_yellow += points/wait_time; break; - case COLOR_TEAM4: + case NUM_TEAM_4: pps_pink += points/wait_time; } total_pps += points/wait_time; @@ -469,12 +469,12 @@ void dom_spawnteams() else numteams = autocvar_g_domination_teams_override; // LordHavoc: edit this if you want to change defaults - dom_spawnteam("Red", COLOR_TEAM1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point"); - dom_spawnteam("Blue", COLOR_TEAM2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point"); + dom_spawnteam("Red", NUM_TEAM_1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point"); + dom_spawnteam("Blue", NUM_TEAM_2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point"); if(numteams > 2) - dom_spawnteam("Yellow", COLOR_TEAM3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point"); + dom_spawnteam("Yellow", NUM_TEAM_3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point"); if(numteams > 3) - dom_spawnteam("Pink", COLOR_TEAM4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point"); + dom_spawnteam("Pink", NUM_TEAM_4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point"); dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, "", "", ""); } diff --git a/qcsrc/server/attic/nexball.qc b/qcsrc/server/attic/nexball.qc index a0e4dc097d..dc9c91ce68 100644 --- a/qcsrc/server/attic/nexball.qc +++ b/qcsrc/server/attic/nexball.qc @@ -427,10 +427,10 @@ void nb_spawnteams (void) { switch(e.team) { - case COLOR_TEAM1: if(!t_r) { nb_spawnteam ("Red", e.team-1) ; t_r = 1; } break; - case COLOR_TEAM2: if(!t_b) { nb_spawnteam ("Blue", e.team-1) ; t_b = 1; } break; - case COLOR_TEAM3: if(!t_y) { nb_spawnteam ("Yellow", e.team-1); t_y = 1; } break; - case COLOR_TEAM4: if(!t_p) { nb_spawnteam ("Pink", e.team-1) ; t_p = 1; } break; + case NUM_TEAM_1: if(!t_r) { nb_spawnteam ("Red", e.team-1) ; t_r = 1; } break; + case NUM_TEAM_2: if(!t_b) { nb_spawnteam ("Blue", e.team-1) ; t_b = 1; } break; + case NUM_TEAM_3: if(!t_y) { nb_spawnteam ("Yellow", e.team-1); t_y = 1; } break; + case NUM_TEAM_4: if(!t_p) { nb_spawnteam ("Pink", e.team-1) ; t_p = 1; } break; } } } @@ -541,22 +541,22 @@ void SpawnGoal (void) void spawnfunc_nexball_redgoal (void) { - self.team = COLOR_TEAM1; + self.team = NUM_TEAM_1; SpawnGoal(); } void spawnfunc_nexball_bluegoal (void) { - self.team = COLOR_TEAM2; + self.team = NUM_TEAM_2; SpawnGoal(); } void spawnfunc_nexball_yellowgoal (void) { - self.team = COLOR_TEAM3; + self.team = NUM_TEAM_3; SpawnGoal(); } void spawnfunc_nexball_pinkgoal (void) { - self.team = COLOR_TEAM4; + self.team = NUM_TEAM_4; SpawnGoal(); } diff --git a/qcsrc/server/attic/runematch.qc b/qcsrc/server/attic/runematch.qc new file mode 100644 index 0000000000..ba8f648c88 --- /dev/null +++ b/qcsrc/server/attic/runematch.qc @@ -0,0 +1,604 @@ +float rune_numspawns; + +float RUNE_FIRST = 1; +float RUNE_STRENGTH = 1; +float RUNE_DEFENSE = 2; +float RUNE_REGEN = 4; +float RUNE_SPEED = 8; +float RUNE_VAMPIRE = 16; +float RUNE_LAST = 16; + +float CURSE_FIRST = 8192; +float CURSE_WEAK = 8192; +float CURSE_VULNER = 16384; +float CURSE_VENOM = 32768; +float CURSE_SLOW = 65536; +float CURSE_EMPATHY = 131072; +float CURSE_LAST = 131072; + +float RUNE_COUNT = 5; + +/* rune ideas: + + Doom/Death + Rune: When you damage enemies, you have a slight chance of instant-killing them (porportional to damage dealt / their health) + Curse: When you are damaged, you have a chance of being instant-killed + + Vengence/Slothful + Rune: The lower your health below 100, the more damage you deal (does not decrease your damage if you're above 100) + Curse: The higher your health (up to 100), the less damage you deal (at 100 hp deal 1/5th damage) + +*/ + +/*QUAKED spawnfunc_runematch_spawn_point (1 0 0) (-16 -16 -24) (16 16 24) +spawn point for runes in runematch +*/ + +void spawnfunc_runematch_spawn_point() +{ + if(!g_runematch || !autocvar_g_runematch_fixedspawns) + { + remove(self); + return; + } + + setsize(self, '0 0 -35', '0 0 0'); + droptofloor(); + ++rune_numspawns; +} + +// only used if using rune spawns at all +entity rune_find_spawnpoint() +{ + entity e; + + if(rune_numspawns < RUNE_COUNT) + return world; + + RandomSelection_Init(); + + for(e = world; (e = find(e, classname, "runematch_spawn_point")); ) + if(e.owner == world) + RandomSelection_Add(e, 0, string_null, e.cnt, 0); + + return RandomSelection_chosen_ent; +} + +float rune_spawn_somewhere(entity e) +{ + entity spot; + spot = rune_find_spawnpoint(); + if(spot) + { + spot.owner = e; + setorigin(e, spot.origin); + + e.owner = spot; + spot.owner = e; + + return TRUE; + } + else + { + if(MoveToRandomMapLocation(e, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256)) + { + // great + makevectors(self.angles), + self.velocity = v_forward * 250; + self.angles = '0 0 0'; + return TRUE; + } + else + { + // sorry, can't spawn, better luck next frame + return FALSE; + } + } +} + +void rune_unmark_spot(entity e) +{ + if(e.owner.classname == "runematch_spawn_point") + { + e.owner.owner = world; + e.owner = world; + } +} + +string RuneName(float r) +{ + if(r == RUNE_STRENGTH) + return "^1Strength^7"; + if(r == RUNE_DEFENSE) + return "^4Defense^7"; + if(r == RUNE_REGEN) + return "^2Vitality^7"; + if(r == RUNE_SPEED) + return "^3Speed^7"; + if(r == RUNE_VAMPIRE) + return "^6Vampire^7"; + + if(r == CURSE_WEAK) + return "^1Weakness^7"; + if(r == CURSE_VULNER) + return "^4Vulnerability^7"; + if(r == CURSE_VENOM) + return "^2Venom^7"; + if(r == CURSE_SLOW) + return "^3Slow^7"; + if(r == CURSE_EMPATHY) + return "^6Empathy^7"; + return strcat("^8[unnamed", ftos(r), "]^7"); +} + +vector RuneColormod(float r) +{ + vector _color = '255 0 255'; + + if(r == RUNE_STRENGTH) + _color = '255 0 0'; + if(r == RUNE_DEFENSE) + _color = '0 0 255';//'0 102 255';// + if(r == RUNE_REGEN) + _color = '0 204 0';//'0 255 0'; + if(r == RUNE_SPEED) + _color = 0.35*'185 185 0';//255 230 0';//'255 255 0'; + if(r == RUNE_VAMPIRE) + _color = '64 0 128';//'108 0 217';//'128 0 255';//'179 0 204';// + + if(r == CURSE_WEAK) + _color = '255 0 0'; + if(r == CURSE_VULNER) + _color = '0 0 255';//'0 102 255';// + if(r == CURSE_VENOM) + _color = '0 204 0';//'0 255 0'; + if(r == CURSE_SLOW) + _color = 0.5*'185 185 0';//'255 255 0'; + if(r == CURSE_EMPATHY) + _color = '179 0 204';//'128 0 255'; + + return _color * (1 / 255) * autocvar_g_runematch_rune_color_strength; +} + +void rune_respawn(); + +void RuneCarriedThink() +{ + float rcount, rnum; + vector ang = '0 0 0'; + entity rune; + + if(self.owner.classname != "player" || time < game_starttime) + { + rune_respawn(); + return; + } + + self.nextthink = time + 0.1; + + // count runes my owner holds + rcount = 0; + rune = find(world, classname, "rune"); + rnum = -1; + while(rune) + { + if(rune.owner == self.owner) + rcount = rcount + 1; + if(rune == self) + rnum = rcount; + rune = find(rune, classname, "rune"); + } + + ang_y = rnum*(360 / rcount) + mod(time, 360)*45;//180; + + makevectors(ang); + + setorigin(self, v_forward*32); +} + +void rune_touch() +{ + if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT) + { + self.think = rune_respawn; + self.nextthink = time; + return; + } + + if(other.classname != "player" || other.health < 1) + return; + if(self.wait > time) + return; // "notouch" time isn't finished + + // detach from the spawn point you're on + rune_unmark_spot(self); + + self.owner = other; + self.enemy.owner = other; + setattachment(self, other, ""); + + other.runes = other.runes | self.runes | self.enemy.runes; + + //self.think = func_null; + //self.nextthink = 0; + self.think = RuneCarriedThink; + self.nextthink = time; + self.touch = func_null; + + self.solid = SOLID_NOT; + setorigin(self, self.origin); + + //sprint(other, strcat("^3You have picked up ", + // RuneName(self.runes & (RUNE_LAST*2-1)), " and ")); + //sprint(other, strcat(RuneName(self.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n")); + + bprint("^3", other.netname, "^7 has picked up ", + RuneName(self.runes & (RUNE_LAST*2-1)), "^7 and "); + bprint(RuneName(self.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n"); +} + +void rune_respawn() +{ + rune_unmark_spot(self); + if(rune_spawn_somewhere(self)) + { + self.solid = SOLID_TRIGGER; + self.touch = rune_touch; + self.think = rune_respawn; + self.nextthink = time + autocvar_g_runematch_shuffletime;//30 + random()*5; // fixme: cvar + } + else + { + // try again later + self.think = rune_respawn; + self.nextthink = time; + } +} + +entity FindRune(entity own, string clname, float r) +{ + entity rune; + float _count, c; + + c = _count = 0; + rune = world; + + do + { + rune = find(rune, classname, clname); + if(!rune) + rune = find(rune, classname, clname); + if(!rune) + break; + if(rune.owner == own) + { + _count = _count + 1; + if(_count >= r) + return rune; + if(r <= 1) + return rune; + } + c = c + 1; + }while(c < 30); + return world; +} + + +void DropRune(entity pl, entity e) +{ + //entity pl; + + //pl = e.owner; + // detach from player + setattachment(e, world, ""); + e.owner = world; + e.enemy.owner = world; + // don't instantly touch player again + e.wait = time + 1; // "notouch" time + e.movetype = MOVETYPE_TOSS; + e.solid = SOLID_TRIGGER; + // reposition itself if not picked up soon + e.think = rune_respawn; + e.nextthink = time + autocvar_g_runematch_respawntime;//15 + random()*5; // fixme: cvar + e.touch = rune_touch; + + pl.runes = pl.runes - (pl.runes & (e.runes | e.enemy.runes)); + + // toss from player + setorigin(e, pl.origin + '0 0 10'); + e.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom(); + + + bprint("^3", pl.netname, "^7 has lost ", + RuneName(e.runes & (RUNE_LAST*2-1)), "^7 and "); + bprint(RuneName(e.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n"); +} + +float RuneMatchesCurse(float r, float c) +{ + float cr; + if(r & RUNE_STRENGTH) + cr = CURSE_WEAK; + else if(r & RUNE_DEFENSE) + cr = CURSE_VULNER; + else if(r & RUNE_REGEN) + cr = CURSE_VENOM; + else if(r & RUNE_SPEED) + cr = CURSE_SLOW; + else if(r & RUNE_VAMPIRE) + cr = CURSE_EMPATHY; + else return FALSE; // fixme: error? + + if(c & cr) + return TRUE; + return FALSE; +} + +// player died, drop runes +// each rune should pair up with a random curse and then be tossed from the player +void DropAllRunes(entity pl) +{ + entity rune, curse; + float rcount, ccount, r, c, rand, prevent_same, numtodrop, tries; + + entity curse1, rune1, curse2, rune2; + + rcount = ccount = r = c = 0; + rune = find(world, classname, "rune"); + while(rune) + { + if(rune.owner == pl) + rcount = rcount + 1; + rune = find(rune, classname, "rune"); + } + curse = find(world, classname, "curse"); + while(curse) + { + if(curse.owner == pl) + ccount = ccount + 1; + curse = find(curse, classname, "curse"); + } + + numtodrop = autocvar_g_runematch_drop_runes_max; + prevent_same = !autocvar_g_runematch_allow_same; + + do + { + rune = find(rune, classname, "rune"); + if(!rune) + break; + if(rune.owner != pl) + continue; + + + // find a random curse + tries = 15; + if(ccount > 1 && prevent_same) + { + // avoid pairing runes and curses that match each other + do{ + rand = floor(random()*ccount) + 1; + curse = FindRune(pl, "curse", rand); + tries = tries - 1; + }while(RuneMatchesCurse(rune.runes, curse.runes) && tries > 0); + if(tries <= 0) + { + bprint("warning: couldn't prevent same rune\n"); + } + } + else + { + rand = floor(random()*ccount) + 1; + curse = FindRune(pl, "curse", rand); + } + + if(!curse) + error("Couldn't fine curse to bind rune to\n"); + + // pair rune and curse + + rune1 = rune; + curse1 = curse; + rune2 = curse1.enemy; + curse2 = rune1.enemy; + + if(rune1 != rune2) // not already attached to each other + { + rune1.enemy = curse1; + curse1.enemy = rune1; + setattachment(curse1, rune1, ""); + rune2.enemy = curse2; + curse2.enemy = rune2; + setattachment(curse2, rune2, ""); + //DropRune(pl, rune2); + //ccount = ccount - 1; + //rcount = rcount - 1; + } + DropRune(pl, rune1); + + if(numtodrop <=0) + { + rune1.think = rune_respawn; + rune1.nextthink = time; + } + + numtodrop = numtodrop - 1; + + ccount = ccount - 1; + rcount = rcount - 1; + + }while(rune); +} + +void rune_reset() +{ + if(self.owner) + if(self.owner.classname != "runematch_spawn_point") + DropAllRunes(self.owner); + rune_respawn(); +} + +void spawn_runes() +{ + float rn, cs, runes_used, curses_used, prevent_same, numrunes; + entity e; + + if(self) + remove(self); + + // fixme: instead of placing them all now, why not + // simply create them all and let them call rune_respawn() as their think? + + runes_used = 0; + curses_used = 0; + + prevent_same = !autocvar_g_runematch_allow_same; + numrunes = RUNE_COUNT; + + while(numrunes > 0) + { + RandomSelection_Init(); + for(rn = RUNE_FIRST; rn <= RUNE_LAST; rn *= 2) + if not(runes_used & rn) + RandomSelection_Add(world, rn, string_null, 1, 1); + rn = RandomSelection_chosen_float; + + RandomSelection_Init(); + for(cs = CURSE_FIRST; cs <= CURSE_LAST; cs *= 2) + if not(curses_used & cs) + if not(prevent_same && cs == RuneMatchesCurse(rn, cs)) + RandomSelection_Add(world, cs, string_null, 1, 1); + cs = RandomSelection_chosen_float; + + if(!rn || !cs) + error("No rune/curse left"); + + runes_used |= rn; + curses_used |= cs; + + e = spawn(); + e.runes = rn; + e.classname = "rune"; + e.touch = rune_touch; + e.think = rune_respawn; + e.nextthink = time; + e.movetype = MOVETYPE_TOSS; + e.solid = SOLID_TRIGGER; + e.flags = FL_ITEM; + e.reset = rune_reset; + setmodel(e, "models/runematch/rune.mdl"); // precision set below + setsize(e, '0 0 -35', '0 0 0'); + + e.enemy = spawn(); + e.enemy.enemy = e; + e.enemy.classname = "curse"; + e.enemy.runes = cs; + //e.enemy.avelocity = '300 500 200'; + setmodel(e.enemy, "models/runematch/curse.mdl"); // precision set below + setorigin(e, '0 0 0'); + setattachment(e.enemy, e, ""); + + e.colormod = RuneColormod(rn); + e.enemy.colormod = RuneColormod(cs); + + e.alpha = e.enemy.alpha = autocvar_g_runematch_rune_alpha;//0.78; + e.effects = e.enemy.effects = autocvar_g_runematch_rune_effects | EF_LOWPRECISION;//EF_ADDITIVE;// | EF_FULLBRIGHT; + + //e.glow_size = e.enemy.glow_size = cvar("g_runematch_rune_glow_size"); + //e.glow_color = e.enemy.glow_color = cvar("g_runematch_rune_glow_color"); + + //rn = RUNE_FIRST; + //cs = CURSE_FIRST; + + numrunes = numrunes - 1; + } +} + +void runematch_init() +{ + if(!g_runematch) + return; + + entity e; + e = spawn(); + e.think = spawn_runes; + e.nextthink = time + 0.1; +} + + +float runematch_point_time; + +// give points to players who are holding runes +void RuneMatchGivePoints() +{ + entity rune; + + if(!g_runematch || !autocvar_g_runematch_pointamt) + return; + + if(gameover) + return; + + if(runematch_point_time > time) + return; + + runematch_point_time = time + autocvar_g_runematch_pointrate; + + rune = world; + do + { + rune = find(rune, classname, "rune"); + if(!rune) + return; + + if(rune.owner.classname == "player") + { + UpdateFrags(rune.owner, autocvar_g_runematch_pointamt); + } + }while(rune); +} + +float RunematchHandleFrags(entity attacker, entity targ, float f) +{ + entity head; + float arunes, trunes, newfrags; + + if(f <= 0) + return f; + if(attacker == targ) + return f; + + arunes = trunes = 0; + + head = find(world, classname, "rune"); + while(head) + { + if(head.owner == attacker) + { + arunes = arunes + 1; + } + else if(head.owner == targ) + { + trunes = trunes + 1; + } + + head = find(head, classname, "rune"); + } + + if(!arunes && !trunes) + return f - 1 + autocvar_g_runematch_frags_norune; // don't give points to players when no runes are involved. + + newfrags = 0; + if(arunes) + { // got a kill while holding runes + newfrags = newfrags + autocvar_g_runematch_frags_killedby_runeholder;//5; + } + if(trunes) + { // killed an enemy holding runes + newfrags = newfrags + autocvar_g_runematch_frags_killed_runeholder;//5; + } + if(newfrags) + f = f - 1 + newfrags; + + return f; +} diff --git a/qcsrc/server/autocvars.qh b/qcsrc/server/autocvars.qh index 08a6297ad4..efb9f8c17a 100644 --- a/qcsrc/server/autocvars.qh +++ b/qcsrc/server/autocvars.qh @@ -75,8 +75,8 @@ float autocvar_g_arena_maxspawned; 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; @@ -178,16 +178,6 @@ float autocvar_g_balance_crylink_secondary_spread; float autocvar_g_balance_crylink_secondary_spreadtype; float autocvar_g_balance_crylink_reload_ammo; float autocvar_g_balance_crylink_reload_time; -float autocvar_g_balance_curse_empathy_minhealth; -float autocvar_g_balance_curse_empathy_takedamage; -float autocvar_g_balance_curse_slow_atkrate; -float autocvar_g_balance_curse_slow_highspeed; -float autocvar_g_balance_curse_venom_hpmod; -float autocvar_g_balance_curse_venom_limitmod; -float autocvar_g_balance_curse_venom_rotrate; -float autocvar_g_balance_curse_vulner_takedamage; -float autocvar_g_balance_curse_weak_damage; -float autocvar_g_balance_curse_weak_force; float autocvar_g_balance_damagepush_speedfactor; float autocvar_g_balance_electro_combo_comboradius; float autocvar_g_balance_electro_combo_damage; @@ -593,26 +583,6 @@ float autocvar_g_balance_rocketlauncher_speedaccel; float autocvar_g_balance_rocketlauncher_speedstart; float autocvar_g_balance_rocketlauncher_reload_ammo; float autocvar_g_balance_rocketlauncher_reload_time; -float autocvar_g_balance_rune_defense_combo_takedamage; -float autocvar_g_balance_rune_defense_takedamage; -float autocvar_g_balance_rune_regen_combo_hpmod; -float autocvar_g_balance_rune_regen_combo_limitmod; -float autocvar_g_balance_rune_regen_combo_regenrate; -float autocvar_g_balance_rune_regen_combo_rotrate; -float autocvar_g_balance_rune_regen_hpmod; -float autocvar_g_balance_rune_regen_limitmod; -float autocvar_g_balance_rune_regen_regenrate; -float autocvar_g_balance_rune_speed_atkrate; -float autocvar_g_balance_rune_speed_combo_atkrate; -float autocvar_g_balance_rune_speed_combo_highspeed; -float autocvar_g_balance_rune_speed_highspeed; -float autocvar_g_balance_rune_strength_combo_damage; -float autocvar_g_balance_rune_strength_combo_force; -float autocvar_g_balance_rune_strength_damage; -float autocvar_g_balance_rune_strength_force; -float autocvar_g_balance_rune_vampire_absorb; -float autocvar_g_balance_rune_vampire_combo_absorb; -float autocvar_g_balance_rune_vampire_maxhealth; float autocvar_g_balance_seeker_type; float autocvar_g_balance_seeker_flac_ammo; float autocvar_g_balance_seeker_flac_animtime; @@ -739,6 +709,8 @@ float autocvar_g_ca_point_leadlimit; 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") @@ -757,6 +729,7 @@ float autocvar_g_chat_flood_spl_team; float autocvar_g_chat_flood_spl_tell; float autocvar_g_chat_nospectators; float autocvar_g_chat_teamcolors; +float autocvar_g_chat_tellprivacy; float autocvar_g_ctf_allow_vehicle_carry; float autocvar_g_ctf_allow_vehicle_touch; float autocvar_g_ctf_throw; @@ -782,7 +755,6 @@ float autocvar_g_ctf_pass_request; float autocvar_g_ctf_pass_turnrate; float autocvar_g_ctf_pass_timelimit; float autocvar_g_ctf_pass_velocity; -float autocvar_g_ctf_captimerecord_always; float autocvar_g_ctf_dynamiclights; string autocvar_g_ctf_flag_blue_model; float autocvar_g_ctf_flag_blue_skin; @@ -792,7 +764,6 @@ float autocvar_g_ctf_flag_dropped_waypoint; float autocvar_g_ctf_flag_dropped_floatinwater; float autocvar_g_ctf_flag_glowtrails; float autocvar_g_ctf_flag_health; -float autocvar_g_ctf_flag_pickup_verbosename; string autocvar_g_ctf_flag_red_model; float autocvar_g_ctf_flag_red_skin; float autocvar_g_ctf_flag_return_time; @@ -845,11 +816,15 @@ string autocvar_g_forced_team_pink; 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") @@ -892,8 +867,8 @@ float autocvar_g_keyhunt_teams; 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; -string autocvar_g_lms_campcheck_message; float autocvar_g_lms_join_anytime; float autocvar_g_lms_last_join; #define autocvar_g_lms_lives_override cvar("g_lms_lives_override") @@ -988,21 +963,6 @@ float autocvar_g_respawn_ghosts; float autocvar_g_respawn_ghosts_maxtime; float autocvar_g_respawn_ghosts_speed; float autocvar_g_respawn_waves; -float autocvar_g_runematch_allow_same; -float autocvar_g_runematch_drop_runes_max; -float autocvar_g_runematch_fixedspawns; -float autocvar_g_runematch_frags_killed_runeholder; -float autocvar_g_runematch_frags_killedby_runeholder; -float autocvar_g_runematch_frags_norune; -float autocvar_g_runematch_point_leadlimit; -#define autocvar_g_runematch_point_limit cvar("g_runematch_point_limit") -float autocvar_g_runematch_pointamt; -float autocvar_g_runematch_pointrate; -float autocvar_g_runematch_respawntime; -float autocvar_g_runematch_rune_alpha; -float autocvar_g_runematch_rune_color_strength; -float autocvar_g_runematch_rune_effects; -float autocvar_g_runematch_shuffletime; float autocvar_g_running_guns; float autocvar_g_shootfromcenter; float autocvar_g_shootfromclient; @@ -1014,7 +974,6 @@ float autocvar_g_spawn_useallspawns; 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; @@ -1163,13 +1122,10 @@ float autocvar_sv_eventlog_files_counter; string autocvar_sv_eventlog_files_nameprefix; string autocvar_sv_eventlog_files_namesuffix; float autocvar_sv_eventlog_files_timestamps; -float autocvar_sv_fraginfo; -float autocvar_sv_fraginfo_handicap; -float autocvar_sv_fraginfo_ping; -float autocvar_sv_fraginfo_stats; float autocvar_sv_friction; float autocvar_sv_friction_on_land; float autocvar_sv_gameplayfix_q2airaccelerate; +float autocvar_sv_gentle; #define autocvar_sv_gravity cvar("sv_gravity") string autocvar_sv_intermission_cdtrack; string autocvar_sv_jumpspeedcap_max; @@ -1272,3 +1228,7 @@ float autocvar_physics_ode; 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; diff --git a/qcsrc/server/bot/aim.qc b/qcsrc/server/bot/aim.qc index 3bff21ecf0..cb42aa5c2c 100644 --- a/qcsrc/server/bot/aim.qc +++ b/qcsrc/server/bot/aim.qc @@ -111,9 +111,8 @@ float bot_shouldattack(entity e) 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. diff --git a/qcsrc/server/bot/bot.qc b/qcsrc/server/bot/bot.qc index 45107b833a..f6e7f6f1b6 100644 --- a/qcsrc/server/bot/bot.qc +++ b/qcsrc/server/bot/bot.qc @@ -398,13 +398,13 @@ void bot_clientconnect() bot_setnameandstuff(); if(self.bot_forced_team==1) - self.team = COLOR_TEAM1; + self.team = NUM_TEAM_1; else if(self.bot_forced_team==2) - self.team = COLOR_TEAM2; + self.team = NUM_TEAM_2; else if(self.bot_forced_team==3) - self.team = COLOR_TEAM3; + self.team = NUM_TEAM_3; else if(self.bot_forced_team==4) - self.team = COLOR_TEAM4; + self.team = NUM_TEAM_4; else JoinBestTeam(self, FALSE, TRUE); @@ -425,13 +425,13 @@ void bot_removefromlargestteam() bestcount = 0; while (head) { - if(head.team == COLOR_TEAM1) + if(head.team == NUM_TEAM_1) thiscount = c1; - else if(head.team == COLOR_TEAM2) + else if(head.team == NUM_TEAM_2) thiscount = c2; - else if(head.team == COLOR_TEAM3) + else if(head.team == NUM_TEAM_3) thiscount = c3; - else if(head.team == COLOR_TEAM4) + else if(head.team == NUM_TEAM_4) thiscount = c4; else thiscount = 0; @@ -551,7 +551,7 @@ float bot_fixcount() 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; } diff --git a/qcsrc/server/bot/havocbot/havocbot.qc b/qcsrc/server/bot/havocbot/havocbot.qc index 1b9178b177..0b8bac7333 100644 --- a/qcsrc/server/bot/havocbot/havocbot.qc +++ b/qcsrc/server/bot/havocbot/havocbot.qc @@ -1,7 +1,6 @@ #include "havocbot.qh" #include "role_onslaught.qc" #include "role_keyhunt.qc" -#include "role_assault.qc" #include "roles.qc" void havocbot_ai() diff --git a/qcsrc/server/bot/havocbot/role_assault.qc b/qcsrc/server/bot/havocbot/role_assault.qc deleted file mode 100644 index 4456802d5c..0000000000 --- a/qcsrc/server/bot/havocbot/role_assault.qc +++ /dev/null @@ -1,205 +0,0 @@ -#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 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); -} diff --git a/qcsrc/server/bot/havocbot/role_onslaught.qc b/qcsrc/server/bot/havocbot/role_onslaught.qc index 6b0ccaa0d5..8071fef74a 100644 --- a/qcsrc/server/bot/havocbot/role_onslaught.qc +++ b/qcsrc/server/bot/havocbot/role_onslaught.qc @@ -127,12 +127,12 @@ void havocbot_goalrating_ons_controlpoints_attack(float ratingscale) continue; // Ignore owned controlpoints - if(self.team == COLOR_TEAM1) + if(self.team == NUM_TEAM_1) { if( (cp2.isgenneighbor_blue || cp2.iscpneighbor_blue) && !(cp2.isgenneighbor_red || cp2.iscpneighbor_red) ) continue; } - else if(self.team == COLOR_TEAM2) + else if(self.team == NUM_TEAM_2) { if( (cp2.isgenneighbor_red || cp2.iscpneighbor_red) && !(cp2.isgenneighbor_blue || cp2.iscpneighbor_blue) ) continue; diff --git a/qcsrc/server/bot/havocbot/roles.qc b/qcsrc/server/bot/havocbot/roles.qc index a3078c4e43..a54874786c 100644 --- a/qcsrc/server/bot/havocbot/roles.qc +++ b/qcsrc/server/bot/havocbot/roles.qc @@ -277,8 +277,6 @@ void havocbot_chooserole() 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(); } diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index be5138c92d..641482155d 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -6,22 +6,6 @@ void send_CSQC_teamnagger() { 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) @@ -293,7 +277,7 @@ entity SelectSpawnPoint (float anypoint) else { float mindist; - if (arena_roundbased && !g_ca) + if (g_arena && arena_roundbased) mindist = 800; else mindist = 100; @@ -401,7 +385,16 @@ void PutObserverInServer (void) WriteEntity(MSG_ONE, self); } - DropAllRunes(self); + 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); @@ -423,14 +416,9 @@ void PutObserverInServer (void) 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) - bprint ("^4", self.netname, "^4 has no more lives left\n"); - else - bprint ("^4", self.netname, "^4 is spectating now\n"); // TODO turn this into a proper forfeit? - } else - bprint ("^4", self.netname, "^4 is spectating now\n"); + 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); @@ -461,7 +449,9 @@ void PutObserverInServer (void) 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; @@ -475,7 +465,6 @@ void PutObserverInServer (void) self.think = func_null; self.nextthink = 0; self.hook_time = 0; - self.runes = 0; self.deadflag = DEAD_NO; self.angles = spot.angles; self.angles_z = 0; @@ -507,45 +496,6 @@ void PutObserverInServer (void) 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; @@ -564,7 +514,7 @@ void FixPlayermodel() if(teamplay) { string s; - s = Team_ColorNameLowerCase(self.team); + s = Team_ColorName_Lower(self.team); if(s != "neutral") { defaultmodel = cvar_string(strcat("sv_defaultplayermodel_", s)); @@ -630,21 +580,6 @@ void FixPlayermodel() 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 @@ -656,11 +591,7 @@ Called when a client spawns in the server 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; @@ -671,21 +602,12 @@ void PutClientInServer (void) // reset player keys self.itemkeys = 0; - // player is dead and becomes observer - // FIXME fix LMS scoring for new system - if(g_lms) - { - if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0) - 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; @@ -699,7 +621,7 @@ void PutClientInServer (void) spot = SelectSpawnPoint (FALSE); if(!spot) { - centerprint(self, "Sorry, no spawnpoints available!\nHope your team can fix it..."); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_NOSPAWNS); return; // spawn failed } @@ -791,7 +713,9 @@ void PutClientInServer (void) } 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; @@ -808,8 +732,6 @@ void PutClientInServer (void) self.metertime = 0; - self.runes = 0; - self.deadflag = DEAD_NO; self.angles = spot.angles; @@ -845,14 +767,6 @@ void PutClientInServer (void) 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; @@ -870,22 +784,13 @@ void PutClientInServer (void) self.colormod = '1 1 1' * autocvar_g_player_brightness; self.exteriorweaponentity.alpha = default_weapon_alpha; - self.lms_nextcheck = time + autocvar_g_lms_campcheck_interval*2; - self.lms_traveled_distance = 0; self.speedrunning = FALSE; race_PostSpawn(spot); //stuffcmd(self, "chase_active 0"); //stuffcmd(self, "set viewsize $tmpviewsize \n"); - - if(g_assault) { - if(self.team == assault_attacker_team) - centerprint(self, "You are attacking!"); - else - centerprint(self, "You are defending!"); - } - + target_voicescript_clear(self); // reset fields the weapons may use @@ -1083,14 +988,13 @@ void ClientKill_Now_TeamChange() } else if(self.killindicator_teamchange == -2) { - if(g_ca) - self.caplayer = 0; if(blockSpectators) - sprint(self, strcat("^7You have to become a player within the next ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n")); + 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() @@ -1152,7 +1056,7 @@ void KillIndicator_Think() 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; @@ -1237,28 +1141,28 @@ void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto, -2 self.killindicator.colormod = '0 0 0'; if(clienttype(self) == CLIENTTYPE_REAL) if(self.killindicator.cnt > 0) - Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "^1Suicide in %d seconds", 1, self.killindicator.cnt); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_SUICIDE, self.killindicator.cnt); } else if(targetteam == -1) // auto { self.killindicator.colormod = '0 1 0'; if(clienttype(self) == CLIENTTYPE_REAL) if(self.killindicator.cnt > 0) - Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "Changing team in %d seconds", 1, self.killindicator.cnt); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_AUTO, self.killindicator.cnt); } else if(targetteam == -2) // spectate { self.killindicator.colormod = '0.5 0.5 0.5'; if(clienttype(self) == CLIENTTYPE_REAL) if(self.killindicator.cnt > 0) - Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "Spectating in %d seconds", 1, self.killindicator.cnt); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_SPECTATE, self.killindicator.cnt); } else { - self.killindicator.colormod = TeamColor(targetteam); + self.killindicator.colormod = Team_ColorRGB(targetteam); if(clienttype(self) == CLIENTTYPE_REAL) if(self.killindicator.cnt > 0) - Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, strcat("Changing to ", ColoredTeamName(targetteam), " in %d seconds"), 1, self.killindicator.cnt); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, APP_TEAM_NUM_4(targetteam, CENTER_TEAMCHANGE_), self.killindicator.cnt); } } @@ -1266,19 +1170,11 @@ void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto, -2 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 @@ -1300,7 +1196,7 @@ void FixClientCvars(entity e) stuffcmd(e, "cl_cmd settemp cl_movecliptokeyboard 2\n"); if(autocvar_g_antilag == 3) // client side hitscan stuffcmd(e, "cl_cmd settemp cl_prydoncursor_notrace 0\n"); - if(sv_gentle) + if(autocvar_sv_gentle) stuffcmd(e, "cl_cmd settemp cl_gentle 1\n"); /* * we no longer need to stuff this. Remove this comment block if you feel @@ -1349,7 +1245,6 @@ ClientConnect Called when a client connects to the server ============= */ -string ColoredTeamName(float t); void DecodeLevelParms (void); //void dom_player_join_team(entity pl); void set_dom_state(entity e); @@ -1369,7 +1264,7 @@ void ClientConnect (void) DecodeLevelParms(); #ifdef WATERMARK - sprint(self, strcat("^4SVQC Build information: ^1", WATERMARK, "\n")); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_WATERMARK, WATERMARK); #endif self.classname = "player_joining"; @@ -1402,30 +1297,30 @@ void ClientConnect (void) { switch(autocvar_g_campaign_forceteam) { - case 1: self.team_forced = COLOR_TEAM1; break; - case 2: self.team_forced = COLOR_TEAM2; break; - case 3: self.team_forced = COLOR_TEAM3; break; - case 4: self.team_forced = COLOR_TEAM4; break; + case 1: self.team_forced = NUM_TEAM_1; break; + case 2: self.team_forced = NUM_TEAM_2; break; + case 3: self.team_forced = NUM_TEAM_3; break; + case 4: self.team_forced = NUM_TEAM_4; break; default: self.team_forced = 0; } } } else if(PlayerInIDList(self, autocvar_g_forced_team_red)) - self.team_forced = COLOR_TEAM1; + self.team_forced = NUM_TEAM_1; else if(PlayerInIDList(self, autocvar_g_forced_team_blue)) - self.team_forced = COLOR_TEAM2; + self.team_forced = NUM_TEAM_2; else if(PlayerInIDList(self, autocvar_g_forced_team_yellow)) - self.team_forced = COLOR_TEAM3; + self.team_forced = NUM_TEAM_3; else if(PlayerInIDList(self, autocvar_g_forced_team_pink)) - self.team_forced = COLOR_TEAM4; + self.team_forced = NUM_TEAM_4; else if(autocvar_g_forced_team_otherwise == "red") - self.team_forced = COLOR_TEAM1; + self.team_forced = NUM_TEAM_1; else if(autocvar_g_forced_team_otherwise == "blue") - self.team_forced = COLOR_TEAM2; + self.team_forced = NUM_TEAM_2; else if(autocvar_g_forced_team_otherwise == "yellow") - self.team_forced = COLOR_TEAM3; + self.team_forced = NUM_TEAM_3; else if(autocvar_g_forced_team_otherwise == "pink") - self.team_forced = COLOR_TEAM4; + self.team_forced = NUM_TEAM_4; else if(autocvar_g_forced_team_otherwise == "spectate") self.team_forced = -1; else if(autocvar_g_forced_team_otherwise == "spectator") @@ -1439,7 +1334,7 @@ void ClientConnect (void) 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) @@ -1477,12 +1372,10 @@ void ClientConnect (void) self.netname_previous = strzone(self.netname); - bprint("^4", self.netname, "^4 connected"); - - if(self.classname != "observer" && (g_domination || g_ctf)) - bprint(" and joined the ", ColoredTeamName(self.team)); - - bprint("\n"); + if((self.classname == STR_PLAYER && teamplay)) + Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(self, INFO_JOIN_CONNECT_TEAM_), self.netname); + else + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_CONNECT, self.netname); stuffcmd(self, strcat(clientstuff, "\n")); stuffcmd(self, "cl_particles_reloadeffects\n"); // TODO do we still need this? @@ -1511,13 +1404,6 @@ void ClientConnect (void) 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(); @@ -1525,7 +1411,7 @@ void ClientConnect (void) self.spectatortime = time; if(blockSpectators) { - sprint(self, strcat("^7You have to become a player within the next ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n")); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime); } self.jointime = time; @@ -1533,17 +1419,14 @@ void ClientConnect (void) 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 != "") @@ -1582,19 +1465,14 @@ void ClientConnect (void) CheatInitClient(); - if(!autocvar_g_campaign) - Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), autocvar_welcome_message_time, 0); - 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); } /* ============= @@ -1638,10 +1516,9 @@ void ClientDisconnect (void) if(autocvar_sv_eventlog) GameLogEcho(strcat(":part:", ftos(self.playerid))); - bprint ("^4",self.netname); - bprint ("^4 disconnected\n"); + + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_DISCONNECT, self.netname); - DropAllRunes(self); MUTATOR_CALLHOOK(ClientDisconnect); Portal_ClearAll(self); @@ -1662,12 +1539,6 @@ void ClientDisconnect (void) bot_relinkplayerlist(); - if(g_arena) - { - Spawnqueue_Unmark(self); - Spawnqueue_Remove(self); - } - accuracy_free(self); ClientData_Detach(); PlayerScore_Detach(self); @@ -1810,7 +1681,8 @@ void player_powerups (void) self.alpha = default_player_alpha; self.exteriorweaponentity.alpha = default_weapon_alpha; self.items &~= IT_STRENGTH; - sprint(self, "^3Invisibility has worn off\n"); + //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_INVISIBILITY, self.netname); + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY); } } else @@ -1820,7 +1692,8 @@ void player_powerups (void) self.alpha = g_minstagib_invis_alpha; self.exteriorweaponentity.alpha = g_minstagib_invis_alpha; self.items |= IT_STRENGTH; - sprint(self, "^3You are invisible\n"); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_INVISIBILITY, self.netname); + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_INVISIBILITY); } } @@ -1830,7 +1703,8 @@ void player_powerups (void) if (time > self.invincible_finished) { self.items = self.items - (self.items & IT_INVINCIBLE); - sprint(self, "^3Speed has worn off\n"); + //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_SPEED, self.netname); + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_SPEED); } } else @@ -1838,7 +1712,8 @@ void player_powerups (void) if (time < self.invincible_finished) { self.items = self.items | IT_INVINCIBLE; - sprint(self, "^3You are on speed\n"); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_SPEED, self.netname); + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_SPEED); } } } @@ -1851,7 +1726,8 @@ void player_powerups (void) if (time > self.strength_finished) { self.items = self.items - (self.items & IT_STRENGTH); - sprint(self, "^3Strength has worn off\n"); + //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_STRENGTH, self.netname); + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_STRENGTH); } } else @@ -1859,7 +1735,8 @@ void player_powerups (void) if (time < self.strength_finished) { self.items = self.items | IT_STRENGTH; - sprint(self, "^3Strength infuses your weapons with devastating power\n"); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_STRENGTH, self.netname); + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_STRENGTH); } } if (self.items & IT_INVINCIBLE) @@ -1869,7 +1746,8 @@ void player_powerups (void) if (time > self.invincible_finished) { self.items = self.items - (self.items & IT_INVINCIBLE); - sprint(self, "^3Shield has worn off\n"); + //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_SHIELD, self.netname); + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_SHIELD); } } else @@ -1877,7 +1755,8 @@ void player_powerups (void) if (time < self.invincible_finished) { self.items = self.items | IT_INVINCIBLE; - sprint(self, "^3Shield surrounds you\n"); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_SHIELD, self.netname); + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_SHIELD); } } if (self.items & IT_SUPERWEAPON) @@ -1886,7 +1765,8 @@ void player_powerups (void) { self.superweapons_finished = 0; self.items = self.items - (self.items & IT_SUPERWEAPON); - sprint(self, "^3Superweapons have been lost\n"); + //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_SUPERWEAPON_LOST, self.netname); + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_SUPERWEAPON_LOST); } else if (self.items & IT_UNLIMITED_SUPERWEAPONS) { @@ -1899,7 +1779,8 @@ void player_powerups (void) { self.items = self.items - (self.items & IT_SUPERWEAPON); WEPSET_ANDNOT_EA(self, WEPBIT_SUPERWEAPONS); - sprint(self, "^3Superweapons have broken down\n"); + //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_SUPERWEAPON_BROKEN, self.netname); + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_SUPERWEAPON_BROKEN); } } } @@ -1908,7 +1789,8 @@ void player_powerups (void) if (time < self.superweapons_finished || (self.items & IT_UNLIMITED_SUPERWEAPONS)) { self.items = self.items | IT_SUPERWEAPON; - sprint(self, "^3You now have a superweapon\n"); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_SUPERWEAPON_PICKUP, self.netname); + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_SUPERWEAPON_PICKUP); } else { @@ -2004,32 +1886,6 @@ void player_regen (void) max_mod = regen_mod = rot_mod = limit_mod = 1; - if (self.runes & RUNE_REGEN) - { - if (self.runes & CURSE_VENOM) // do we have both rune/curse? - { - regen_mod = autocvar_g_balance_rune_regen_combo_regenrate; - max_mod = autocvar_g_balance_rune_regen_combo_hpmod; - limit_mod = autocvar_g_balance_rune_regen_combo_limitmod; - } - else - { - regen_mod = autocvar_g_balance_rune_regen_regenrate; - max_mod = autocvar_g_balance_rune_regen_hpmod; - limit_mod = autocvar_g_balance_rune_regen_limitmod; - } - } - else if (self.runes & CURSE_VENOM) - { - max_mod = autocvar_g_balance_curse_venom_hpmod; - if (self.runes & RUNE_REGEN) // do we have both rune/curse? - rot_mod = autocvar_g_balance_rune_regen_combo_rotrate; - else - rot_mod = autocvar_g_balance_curse_venom_rotrate; - limit_mod = autocvar_g_balance_curse_venom_limitmod; - //if (!self.runes & RUNE_REGEN) - // rot_mod = autocvar_g_balance_curse_venom_rotrate; - } maxh = maxh * max_mod; //maxa = maxa * max_mod; //maxf = maxf * max_mod; @@ -2040,7 +1896,7 @@ void player_regen (void) 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)) @@ -2165,7 +2021,6 @@ void SpectateCopy(entity spectatee) { 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); @@ -2216,6 +2071,46 @@ float SpectateUpdate() { } +float SpectateSet() +{ + if(self.enemy.classname != "player") + return FALSE; + /*if(self.enemy.vehicle) + { + + msg_entity = self; + WriteByte(MSG_ONE, SVC_SETVIEW); + WriteEntity(MSG_ONE, self.enemy); + //stuffcmd(self, "set viewsize $tmpviewsize \n"); + + self.movetype = MOVETYPE_NONE; + accuracy_resend(self); + } + else + {*/ + msg_entity = self; + WriteByte(MSG_ONE, SVC_SETVIEW); + WriteEntity(MSG_ONE, self.enemy); + //stuffcmd(self, "set viewsize $tmpviewsize \n"); + self.movetype = MOVETYPE_NONE; + accuracy_resend(self); + + if(!SpectateUpdate()) + PutObserverInServer(); + //} + return TRUE; +} + +float Spectate(entity pl) +{ + if(g_ca && !autocvar_g_ca_spectate_enemies && self.caplayer) + if(pl.team != self.team) + return 0; + + self.enemy = pl; + return SpectateSet(); +} + // Returns next available player to spectate if g_ca_spectate_enemies == 0 entity CA_SpectateNext(entity start) { if (start.team == self.team) { @@ -2239,13 +2134,10 @@ entity CA_SpectateNext(entity start) { return other; } -float SpectateNext(entity _prefer) { - - if(_prefer) - other = _prefer; - else - other = find(self.enemy, classname, "player"); - +float SpectateNext() +{ + other = find(self.enemy, classname, "player"); + if (g_ca && !autocvar_g_ca_spectate_enemies && self.caplayer) { // CA and ca players when spectating enemies is forbidden other = CA_SpectateNext(other); @@ -2254,38 +2146,49 @@ float SpectateNext(entity _prefer) { if (!other) other = find(other, classname, "player"); } - + if (other) self.enemy = other; - if(self.enemy.classname == "player") { - /*if(self.enemy.vehicle) - { - - msg_entity = self; - WriteByte(MSG_ONE, SVC_SETVIEW); - WriteEntity(MSG_ONE, self.enemy); - //stuffcmd(self, "set viewsize $tmpviewsize \n"); - - self.movetype = MOVETYPE_NONE; - accuracy_resend(self); - } - else - {*/ - msg_entity = self; - WriteByte(MSG_ONE, SVC_SETVIEW); - WriteEntity(MSG_ONE, self.enemy); - //stuffcmd(self, "set viewsize $tmpviewsize \n"); - self.movetype = MOVETYPE_NONE; - accuracy_resend(self); - - if(!SpectateUpdate()) - PutObserverInServer(); - //} - return 1; - } else { - return 0; + return SpectateSet(); +} + +float SpectatePrev() +{ + // NOTE: chain order is from the highest to the lower entnum (unlike find) + other = findchain(classname, "player"); + if not(other) // no player + return FALSE; + + entity first = other; + // skip players until current spectated player + if(self.enemy) + while(other && other != self.enemy) + other = other.chain; + + if (g_ca && !autocvar_g_ca_spectate_enemies && self.caplayer) + { + do { other = other.chain; } + while(other && other.team != self.team); + + if not(other) + { + other = first; + while(other.team != self.team) + other = other.chain; + if(other == self.enemy) + return TRUE; + } + } + else + { + if(other.chain) + other = other.chain; + else + other = first; } + self.enemy = other; + return SpectateSet(); } /* @@ -2309,55 +2212,40 @@ void ShowRespawnCountdown() { 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)); } } } -.float prevent_join_msgtime; void LeaveSpectatorMode() { - if(nJoinAllowed(self)) { - if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0) { + 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) + { self.classname = "player"; if(autocvar_g_campaign || autocvar_g_balance_teams) - JoinBestTeam(self, FALSE, TRUE); + { JoinBestTeam(self, FALSE, TRUE); } if(autocvar_g_campaign) - campaign_bots_may_start = 1; - - PutClientInServer(); - - if(self.classname == "player") - bprint ("^4", self.netname, "^4 is playing now\n"); + { campaign_bots_may_start = 1; } - if(!autocvar_g_campaign) - if (time < self.jointime + autocvar_welcome_message_time) - Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD); // clear MOTD + Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN); - if (self.prevent_join_msgtime) - { - Send_CSQC_Centerprint_Generic_Expire(self, CPID_PREVENT_JOIN); - self.prevent_join_msgtime = 0; - } + PutClientInServer(); - return; - } else { - if (g_ca && self.caplayer) { - } // do nothing - else - stuffcmd(self,"menu_showteamselect\n"); - return; + if(IS_PLAYER(self)) { Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_PLAY, self.netname); } } + else + stuffcmd(self, "menu_showteamselect\n"); } - else { - //player may not join because of g_maxplayers is set - if (time - self.prevent_join_msgtime > 2) - { - Send_CSQC_Centerprint_Generic(self, CPID_PREVENT_JOIN, PREVENT_JOIN_TEXT, 0, 0); - self.prevent_join_msgtime = time; - } + else + { + // Player may not join because g_maxplayers is set + Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_PREVENT); } } @@ -2392,8 +2280,9 @@ float nJoinAllowed(entity ignore) { 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); @@ -2408,46 +2297,57 @@ float nJoinAllowed(entity ignore) { void checkSpectatorBlock() { if(self.classname == "spectator" || self.classname == "observer") { if( time > (self.spectatortime + autocvar_g_maxplayers_spectator_blocktime) ) { - sprint(self, "^7You were kicked from the server because you are spectator and spectators aren't allowed at the moment.\n"); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_QUIT_KICK_SPECTATING); dropclient(self); } } } -.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_CSQC_Centerprint_Generic(self, CPID_MOTD, campaign_message, -1, 0); + 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_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), -1, 0); + 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; else if ((time - self.motd_actived_time > 2) && self.classname == "player") { // hide it some seconds after BUTTON_INFO has been released self.motd_actived_time = 0; - Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD); + 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; - Send_CSQC_Centerprint_Generic_Expire(self, 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() @@ -2459,7 +2359,7 @@ void ObserverThink() self.flags |= FL_SPAWNING; } else if(self.BUTTON_ATCK && !self.version_mismatch) { self.flags &~= FL_JUMPRELEASED; - if(SpectateNext(world) == 1) { + if(SpectateNext()) { self.classname = "spectator"; } } else { @@ -2478,8 +2378,6 @@ void ObserverThink() } } } - - PrintWelcomeMessage(); } void SpectatorThink() @@ -2488,14 +2386,24 @@ void SpectatorThink() if (self.BUTTON_JUMP && !self.version_mismatch) { self.flags &~= FL_JUMPRELEASED; self.flags |= FL_SPAWNING; - } else if(self.BUTTON_ATCK) { + } else if(self.BUTTON_ATCK || self.impulse == 10 || self.impulse == 15 || self.impulse == 18 || self.impulse >= 200 && self.impulse <= 209) { self.flags &~= FL_JUMPRELEASED; - if(SpectateNext(world) == 1) { + if(SpectateNext()) { self.classname = "spectator"; } else { self.classname = "observer"; PutClientInServer(); } + self.impulse = 0; + } else if(self.impulse == 12 || self.impulse == 16 || self.impulse == 19 || self.impulse >= 220 && self.impulse <= 229) { + self.flags &~= FL_JUMPRELEASED; + if(SpectatePrev()) { + self.classname = "spectator"; + } else { + self.classname = "observer"; + PutClientInServer(); + } + self.impulse = 0; } else if (self.BUTTON_ATCK2) { self.flags &~= FL_JUMPRELEASED; self.classname = "observer"; @@ -2518,7 +2426,6 @@ void SpectatorThink() PutObserverInServer(); } - PrintWelcomeMessage(); self.flags |= FL_CLIENT | FL_NOTARGET; } @@ -2537,8 +2444,6 @@ void PlayerUseKey() MUTATOR_CALLHOOK(PlayerUseKey); } -.float touchexplode_time; - /* ============= PlayerPreThink @@ -2554,14 +2459,10 @@ void PlayerPreThink (void) 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 @@ -2595,7 +2496,7 @@ void PlayerPreThink (void) { // notify release users if connecting to git dprint("^1NOTE^7 to ", self.netname, "^7 - the server is running ^3Xonotic ", autocvar_g_xonoticversion, " (beta)^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n"); - sprint(self, strcat("\{1}^1NOTE: ^7the server is running ^3Xonotic ", autocvar_g_xonoticversion, " (beta)^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n")); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_VERSION_BETA, autocvar_g_xonoticversion, self.cvar_g_xonoticversion); } else { @@ -2605,13 +2506,13 @@ void PlayerPreThink (void) { // give users new version dprint("^1NOTE^7 to ", self.netname, "^7 - ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.org/^1!\n"); - sprint(self, strcat("\{1}^1NOTE: ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.org/^1!\n")); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_VERSION_OUTDATED, autocvar_g_xonoticversion, self.cvar_g_xonoticversion); } else if(r > 0) { // notify users about old server version print("^1NOTE^7 to ", self.netname, "^7 - the server is running ^3Xonotic ", autocvar_g_xonoticversion, "^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n"); - sprint(self, strcat("\{1}^1NOTE: ^7the server is running ^3Xonotic ", autocvar_g_xonoticversion, "^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n")); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_VERSION_OLD, autocvar_g_xonoticversion, self.cvar_g_xonoticversion); } } } @@ -2621,7 +2522,7 @@ void PlayerPreThink (void) // GOD MODE info if(!(self.flags & FL_GODMODE)) if(self.max_armorvalue) { - sprint(self, strcat("godmode saved you ", ftos(self.max_armorvalue), " units of damage, cheater!\n")); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_GODMODE_OFF, self.max_armorvalue); self.max_armorvalue = 0; } @@ -2639,11 +2540,10 @@ void PlayerPreThink (void) 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(); @@ -2687,25 +2587,26 @@ void PlayerPreThink (void) 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; @@ -2728,7 +2629,13 @@ void PlayerPreThink (void) 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 @@ -2737,55 +2644,6 @@ void PlayerPreThink (void) 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) - { - centerprint(self, autocvar_g_lms_campcheck_message); - // 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; @@ -2976,11 +2834,7 @@ void PlayerPostThink (void) { if (time - self.parm_idlesince < 1) // instead of (time == self.parm_idlesince) to support sv_maxidle <= 10 { - if(self.idlekick_lasttimeleft) - { - Send_CSQC_Centerprint_Generic_Expire(self, CPID_DISCONNECT_IDLING); - self.idlekick_lasttimeleft = 0; - } + if(self.idlekick_lasttimeleft) { self.idlekick_lasttimeleft = 0; } } else { @@ -2989,19 +2843,18 @@ void PlayerPostThink (void) if(timeleft == min(10, sv_maxidle - 1)) // - 1 to support sv_maxidle <= 10 { if(!self.idlekick_lasttimeleft) - Send_CSQC_Centerprint_Generic(self, CPID_DISCONNECT_IDLING, "^3Stop idling!\n^3Disconnecting in %d seconds...", 1, timeleft); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_DISCONNECT_IDLING, timeleft); } if(timeleft <= 0) { - bprint("^3", self.netname, "^3 was kicked for idling.\n"); - AnnounceTo(self, "terminated"); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_KICK_IDLING, self.netname); dropclient(self); return; } 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; } } diff --git a/qcsrc/server/cl_impulse.qc b/qcsrc/server/cl_impulse.qc index 529567a3b4..d09c0704fe 100644 --- a/qcsrc/server/cl_impulse.qc +++ b/qcsrc/server/cl_impulse.qc @@ -46,6 +46,10 @@ void ImpulseCommands (void) 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; diff --git a/qcsrc/server/cl_physics.qc b/qcsrc/server/cl_physics.qc index 50401604ef..a318b8e3a4 100644 --- a/qcsrc/server/cl_physics.qc +++ b/qcsrc/server/cl_physics.qc @@ -48,13 +48,7 @@ void PlayerJump (void) 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; } @@ -358,7 +352,7 @@ void RaceCarPhysics() 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; @@ -712,20 +706,6 @@ void SV_PlayerPhysics() else if(g_keepaway) maxspd_mod *= autocvar_g_keepaway_ballcarrier_highspeed; - if(g_runematch) - { - if(self.runes & RUNE_SPEED) - { - if(self.runes & CURSE_SLOW) - maxspd_mod *= autocvar_g_balance_rune_speed_combo_highspeed; - else - maxspd_mod *= autocvar_g_balance_rune_speed_highspeed; - } - else if(self.runes & CURSE_SLOW) - { - maxspd_mod *= autocvar_g_balance_curse_slow_highspeed; - } - } maxspd_mod *= autocvar_g_movement_highspeed; // fix physics stats for g_movement_highspeed diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index e81b08e58e..60df5dd314 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -338,7 +338,6 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float } void ClientKill_Now_TeamChange(); -void freezetag_CheckWinner(); void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) { @@ -347,9 +346,6 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht 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); @@ -467,7 +463,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht { self.pain_finished = time + 0.5; //Supajoe - if(sv_gentle < 1) { + if(autocvar_sv_gentle < 1) { if(self.classname != "body") // pain anim is BORKED on our ZYMs, FIXME remove this once we have good models { if (!self.animstate_override) @@ -554,7 +550,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht if(valid_damage_for_weaponstats) WeaponStats_LogKill(awep, abot, self.weapon, vbot); - if(sv_gentle < 1) // TODO make a "gentle" version? + if(autocvar_sv_gentle < 1) // TODO make a "gentle" version? if(sound_allowed(MSG_BROADCAST, attacker)) { if(deathtype == DEATH_DROWN) @@ -579,18 +575,9 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht } } - 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(); - DropAllRunes(self); // increment frag counter for used weapon type float w; @@ -599,18 +586,12 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht 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); @@ -619,7 +600,6 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht if(clienttype(self) == CLIENTTYPE_REAL) { - stuffcmd(self, "-zoom\n"); self.fixangle = TRUE; //msg_entity = self; //WriteByte (MSG_ONE, SVC_SETANGLE); @@ -628,19 +608,23 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht //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; @@ -679,6 +663,10 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht self.respawn_countdown = 10; // first number to count down from is 10 else self.respawn_countdown = -1; // do not count down + + if(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); @@ -696,7 +684,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht // set up to fade out later SUB_SetFade (self, time + 6 + random (), 1); - if(sv_gentle > 0 || autocvar_ekg) { + if(autocvar_sv_gentle > 0 || autocvar_ekg) { // remove corpse PlayerCorpseDamage (inflictor, attacker, autocvar_sv_gibhealth+1.0, deathtype, hitloc, force); } @@ -933,17 +921,18 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f if(sourcecmsgstr != "" && !privatesay) centerprint(source, sourcecmsgstr); } - else if(privatesay) // private message, between 2 people only, not sent to server console + else if(privatesay) // private message, between 2 people only { sprint(source, sourcemsgstr); sprint(privatesay, msgstr); + if not(autocvar_g_chat_tellprivacy) { dedicated_print(msgstr); } // send to server console too if "tellprivacy" is disabled if(cmsgstr != "") centerprint(privatesay, cmsgstr); } else if(teamsay > 0) // team message, only sent to team mates { sprint(source, sourcemsgstr); - //print(msgstr); // send to server console too + dedicated_print(msgstr); // send to server console too if(sourcecmsgstr != "") centerprint(source, sourcecmsgstr); FOR_EACH_REALPLAYER(head) if(head.team == source.team) @@ -957,7 +946,7 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f else if(teamsay < 0) // spectator message, only sent to spectators { sprint(source, sourcemsgstr); - //print(msgstr); // send to server console too + dedicated_print(msgstr); // send to server console too FOR_EACH_REALCLIENT(head) if(head.classname != "player") if(head != source) sprint(head, msgstr); @@ -965,7 +954,7 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f else if(sourcemsgstr != msgstr) // trimmed/server fixed message, sent to all players { sprint(source, sourcemsgstr); - //print(msgstr); // send to server console too + dedicated_print(msgstr); // send to server console too FOR_EACH_REALCLIENT(head) if(head != source) sprint(head, msgstr); @@ -1147,7 +1136,7 @@ void FakeGlobalSound(string sample, float chan, float voicetype) break; if(!sv_taunt) break; - if(sv_gentle) + if(autocvar_sv_gentle) break; tauntrand = random(); msg_entity = self; @@ -1165,7 +1154,7 @@ void FakeGlobalSound(string sample, float chan, float voicetype) animdecide_setaction(self, ANIMACTION_TAUNT, TRUE); if(!sv_taunt) break; - if(sv_gentle) + if(autocvar_sv_gentle) break; msg_entity = self; if (msg_entity.cvar_cl_voice_directional >= 1) @@ -1244,7 +1233,7 @@ void GlobalSound(string sample, float chan, float voicetype) break; if(!sv_taunt) break; - if(sv_gentle) + if(autocvar_sv_gentle) break; tauntrand = random(); FOR_EACH_REALCLIENT(msg_entity) @@ -1262,7 +1251,7 @@ void GlobalSound(string sample, float chan, float voicetype) animdecide_setaction(self, ANIMACTION_TAUNT, TRUE); if(!sv_taunt) break; - if(sv_gentle) + if(autocvar_sv_gentle) break; FOR_EACH_REALCLIENT(msg_entity) { @@ -1310,14 +1299,8 @@ void VoiceMessage(string type, string msg) FakeGlobalSound(self.sample, CH_VOICE, voicetype); } -void MoveToTeam(entity client, float team_colour, float type, float show_message) +void MoveToTeam(entity client, float team_colour, float type) { -// show_message -// 0 (00) automove centerprint, admin message -// 1 (01) automove centerprint, no admin message -// 2 (10) no centerprint, admin message -// 3 (11) no centerprint, no admin message - float lockteams_backup; lockteams_backup = lockteams; // backup any team lock @@ -1326,14 +1309,9 @@ void MoveToTeam(entity client, float team_colour, float type, float show_message TeamchangeFrags(client); // move the players frags SetPlayerColors(client, team_colour - 1); // set the players colour - Damage(client, client, client, 100000, ((show_message & 2) ? DEATH_QUIET : DEATH_AUTOTEAMCHANGE), client.origin, '0 0 0'); // kill the player + Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE, client.origin, '0 0 0'); // kill the player lockteams = lockteams_backup; // restore the team lock LogTeamchange(client.playerid, client.team, type); - - if not(show_message & 1) // admin message - sprint(client, strcat("\{1}\{13}^3", admin_name(), "^7: You have been moved to the ", Team_ColorNameLowerCase(team_colour), " team\n")); // send a chat message - - bprint(strcat(client.netname, " joined the ", ColoredTeamName(client.team), "\n")); } diff --git a/qcsrc/server/cl_weapons.qc b/qcsrc/server/cl_weapons.qc index 4df59a09af..0014e9182d 100644 --- a/qcsrc/server/cl_weapons.qc +++ b/qcsrc/server/cl_weapons.qc @@ -158,16 +158,6 @@ float weapon_action(float wpn, float wrequest) return (get_weaponinfo(wpn)).weapon_func(wrequest); } -string W_Name(float weaponid) -{ - return (get_weaponinfo(weaponid)).message; -} - -float W_AmmoItemCode(float wpn) -{ - return (get_weaponinfo(wpn)).items & IT_AMMO; -} - .float savenextthink; void thrown_wep_think() { @@ -311,10 +301,6 @@ float W_IsWeaponThrowable(float w) 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) @@ -359,15 +345,24 @@ void W_ThrowWeapon(vector velo, vector delta, float doreduce) W_SwitchWeapon_Force(self, w_getbestweapon(self)); a = W_ThrowNewWeapon(self, w, doreduce, self.origin + delta, velo); - if not(a) - return; - if(a == "") - sprint(self, strcat("You dropped the ^2", W_Name(w), "\n")); - else - sprint(self, strcat("You dropped the ^2", W_Name(w), " with ", a, "\n")); + + if not(a) return; + Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_WEAPON_DROP, a, w); +} + +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; } -// Bringed back weapon frame void W_WeaponFrame() { vector fo, ri, up; @@ -375,15 +370,16 @@ void W_WeaponFrame() 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; diff --git a/qcsrc/server/cl_weaponsystem.qc b/qcsrc/server/cl_weaponsystem.qc index f697d3689c..afabe18202 100644 --- a/qcsrc/server/cl_weaponsystem.qc +++ b/qcsrc/server/cl_weaponsystem.qc @@ -14,21 +14,6 @@ float W_WeaponRateFactor() float t; t = 1.0 / g_weaponratefactor; - if(g_runematch) - { - if(self.runes & RUNE_SPEED) - { - if(self.runes & CURSE_SLOW) - t = t * autocvar_g_balance_rune_speed_combo_atkrate; - else - t = t * autocvar_g_balance_rune_speed_atkrate; - } - else if(self.runes & CURSE_SLOW) - { - t = t * autocvar_g_balance_curse_slow_atkrate; - } - } - return t; } @@ -714,7 +699,6 @@ float client_hasweapon(entity cl, float wpn, float andammo, float complain) if(clienttype(cl) == CLIENTTYPE_REAL) { play2(cl, "weapons/unavailable.wav"); - sprint(cl, strcat("You don't have any ammo for the ^2", W_Name(wpn), "\n")); Send_WeaponComplain (cl, wpn, W_Name(wpn), 0); } return FALSE; @@ -728,8 +712,7 @@ float client_hasweapon(entity cl, float wpn, float andammo, float complain) // Report Proper Weapon Status / Modified Weapon Ownership Message if (WEPSET_CONTAINS_AW(weaponsInMap, wpn)) { - sprint(cl, strcat("You do not have the ^2", W_Name(wpn), "\n") ); - Send_WeaponComplain (cl, wpn, W_Name(wpn), 1); + Send_WeaponComplain(cl, wpn, W_Name(wpn), 1); if(autocvar_g_showweaponspawns) { @@ -760,7 +743,6 @@ float client_hasweapon(entity cl, float wpn, float andammo, float complain) else { Send_WeaponComplain (cl, wpn, W_Name(wpn), 2); - sprint(cl, strcat("The ^2", W_Name(wpn), "^7 is ^1NOT AVAILABLE^7 in this map\n") ); } play2(cl, "weapons/unavailable.wav"); @@ -823,14 +805,6 @@ void W_SwitchToOtherWeapon(entity pl) W_SwitchWeapon_Force(pl, ww); } -string PrimaryOrSecondary(float secondary) -{ - if(secondary) - return "secondary"; - else - return "primary"; -} - .float prevdryfire; .float prevwarntime; float weapon_prepareattack_checkammo(float secondary) @@ -854,7 +828,15 @@ float weapon_prepareattack_checkammo(float secondary) { if(time - self.prevwarntime > 1) { - sprint(self, strcat("^2", W_Name(self.weapon), " ", PrimaryOrSecondary(secondary), "^7 is unable to fire, but its ^2", PrimaryOrSecondary(1 - secondary), "^7 can.\n")); + Send_Notification( + NOTIF_ONE, + self, + MSG_MULTI, + ITEM_WEAPON_PRIMORSEC, + self.weapon, + secondary, + (1 - secondary) + ); } self.prevwarntime = time; } diff --git a/qcsrc/server/command/cmd.qc b/qcsrc/server/command/cmd.qc index 530646afd2..e22399f4ac 100644 --- a/qcsrc/server/command/cmd.qc +++ b/qcsrc/server/command/cmd.qc @@ -154,18 +154,18 @@ void ClientCommand_join(float request) { if(nJoinAllowed(self)) { - if(g_ca) { self.caplayer = 1; } if(autocvar_g_campaign) { campaign_bots_may_start = 1; } - + self.classname = "player"; PlayerScore_Clear(self); - bprint ("^4", self.netname, "^4 is playing now\n"); + 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 - centerprint(self, PREVENT_JOIN_TEXT); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_PREVENT); } } } @@ -194,6 +194,8 @@ void ClientCommand_ready(float request) // todo: anti-spam for toggling readynes { if(!readyrestart_happened || autocvar_sv_ready_restart_repeatable) { + if(time < game_starttime) // game is already restarting + return; if (self.ready) // toggle { self.ready = FALSE; @@ -284,10 +286,10 @@ void ClientCommand_selectteam(float request, float argc) switch(argv(1)) { - case "red": selection = COLOR_TEAM1; break; - case "blue": selection = COLOR_TEAM2; break; - case "yellow": selection = COLOR_TEAM3; break; - case "pink": selection = COLOR_TEAM4; break; + case "red": selection = NUM_TEAM_1; break; + case "blue": selection = NUM_TEAM_2; break; + case "yellow": selection = NUM_TEAM_3; break; + case "pink": selection = NUM_TEAM_4; break; case "auto": selection = (-1); break; default: selection = 0; break; @@ -397,6 +399,8 @@ void ClientCommand_spectate(float request) { if(self.lms_spectate_warning) { + // for the forfeit message... + self.lms_spectate_warning = 2; // mark player as spectator PlayerScore_Add(self, SP_LMS_RANK, 666 - PlayerScore_Add(self, SP_LMS_RANK, 0)); } @@ -410,10 +414,10 @@ void ClientCommand_spectate(float request) 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; diff --git a/qcsrc/server/command/common.qc b/qcsrc/server/command/common.qc index 53ad41d355..132a0af70e 100644 --- a/qcsrc/server/command/common.qc +++ b/qcsrc/server/command/common.qc @@ -162,14 +162,9 @@ void print_to(entity to, string input) // used by CommonCommand_timeout() and CommonCommand_timein() to handle game pausing and messaging and such. void timeout_handler_reset() { - entity tmp_player; - timeout_caller = world; timeout_time = 0; timeout_leadtime = 0; - - FOR_EACH_REALPLAYER(tmp_player) - Send_CSQC_Centerprint_Generic_Expire(tmp_player, CPID_TIMEOUT_COUNTDOWN); remove(self); } @@ -184,11 +179,10 @@ void timeout_handler_think() { if(timeout_time > 0) // countdown is still going { - FOR_EACH_REALPLAYER(tmp_player) - Send_CSQC_Centerprint_Generic(tmp_player, CPID_TIMEOUT_COUNTDOWN, "Timeout ends in %d seconds!", 1, timeout_time); + 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 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 @@ -214,9 +208,7 @@ void timeout_handler_think() { if(timeout_leadtime > 0) // countdown is still going { - // centerprint the information to every player - FOR_EACH_REALPLAYER(tmp_player) - Send_CSQC_Centerprint_Generic(tmp_player, CPID_TIMEOUT_COUNTDOWN, "Timeout begins in %d seconds!", 1, timeout_leadtime); + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_TIMEOUT_BEGINNING, timeout_leadtime); self.nextthink = time + 1; // think again in one second timeout_leadtime -= 1; // decrease the time counter @@ -583,7 +575,7 @@ void CommonCommand_timeout(float request, entity caller) // DEAR GOD THIS COMMAN 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"); } @@ -607,7 +599,7 @@ void CommonCommand_who(float request, entity caller, float argc) { case CMD_REQUEST_COMMAND: { - float total_listed_players, tmp_hours, tmp_minutes, tmp_seconds, is_bot; + float total_listed_players, is_bot; entity tmp_player; float privacy = (caller && autocvar_sv_status_privacy); @@ -638,22 +630,13 @@ void CommonCommand_who(float request, entity caller, float argc) tmp_netaddress = tmp_player.netaddress; tmp_crypto_idfp = tmp_player.crypto_idfp; } - - tmp_hours = tmp_minutes = tmp_seconds = 0; - - tmp_seconds = floor(time - tmp_player.jointime); - tmp_minutes = floor(tmp_seconds / 60); - tmp_hours = floor(tmp_minutes / 60); - - if(tmp_minutes) { tmp_seconds -= (tmp_minutes * 60); } - if(tmp_hours) { tmp_minutes -= (tmp_hours * 60); } print_to(caller, sprintf(strreplace(" ", separator, " #%-3d %-20.20s %-5d %-3d %-9s %-16s %s "), num_for_edict(tmp_player), tmp_player.netname, tmp_player.ping, tmp_player.ping_packetloss, - sprintf("%02d:%02d:%02d", tmp_hours, tmp_minutes, tmp_seconds), + process_time(1, time - tmp_player.jointime), tmp_netaddress, tmp_crypto_idfp)); diff --git a/qcsrc/server/command/getreplies.qc b/qcsrc/server/command/getreplies.qc index 0bedd6d5e2..39206966cf 100644 --- a/qcsrc/server/command/getreplies.qc +++ b/qcsrc/server/command/getreplies.qc @@ -96,7 +96,7 @@ string getrankings() continue; n = race_readName(map, i); - p = race_placeName(i); + p = count_ordinal(i); s = strcat(s, strpad(8, p), " ", strpad(-8, TIME_ENCODED_TOSTRING(t)), " ", n, "\n"); } @@ -240,7 +240,7 @@ string getladder() s = strcat(s, " ^7Total ^3|"); for(i = 1; i <= LADDER_CNT; ++i) - { s = strcat(s, " ^7", race_placeName(i), " ^3|"); } + { s = strcat(s, " ^7", count_ordinal(i), " ^3|"); } s = strcat(s, " ^7Speed awards ^3| ^7Name"); s = strcat(s, "\n^3----+--------"); @@ -263,7 +263,7 @@ string getladder() if(argv(LADDER_CNT+1) == "") // total is 0, skip continue; - s = strcat(s, strpad(4, race_placeName(i+1)), "^3| ^7"); // pos + s = strcat(s, strpad(4, count_ordinal(i+1)), "^3| ^7"); // pos s = strcat(s, strpad(7, argv(LADDER_CNT+1)), "^3| ^7"); // total for(j = 1; j <= min(9, LADDER_CNT); ++j) diff --git a/qcsrc/server/command/sv_cmd.qc b/qcsrc/server/command/sv_cmd.qc index 8f3ea869d4..0944f04fbb 100644 --- a/qcsrc/server/command/sv_cmd.qc +++ b/qcsrc/server/command/sv_cmd.qc @@ -972,7 +972,6 @@ void GameCommand_moveplayer(float request, float argc) string targets = strreplace(",", " ", argv(1)); string original_targets = strreplace(" ", ", ", targets); string destination = argv(2); - string notify = argv(3); string successful, t; successful = string_null; @@ -1017,21 +1016,21 @@ void GameCommand_moveplayer(float request, float argc) if(teamplay) { // set up - float team_color; + float team_id; float save = client.team_forced; client.team_forced = 0; // find the team to move the player to - team_color = ColourToNumber(destination); - if(team_color == client.team) // already on the destination team + team_id = Team_ColorToTeam(destination); + if(team_id == client.team) // already on the destination team { // keep the forcing undone - print("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") is already on the ", ColoredTeamName(client.team), (targets ? ", skipping to next player.\n" : ".\n")); + print("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") is already on the ", Team_ColoredFullName(client.team), (targets ? "^7, skipping to next player.\n" : "^7.\n")); continue; } - else if(team_color == 0) // auto team + else if(team_id == 0) // auto team { - team_color = NumberToTeamNumber(FindSmallestTeam(client, FALSE)); + team_id = Team_NumberToTeam(FindSmallestTeam(client, FALSE)); } else { @@ -1040,21 +1039,21 @@ void GameCommand_moveplayer(float request, float argc) client.team_forced = save; // Check to see if the destination team is even available - switch(team_color) + switch(team_id) { - case COLOR_TEAM1: if(c1 == -1) { print("Sorry, can't move player to red team if it doesn't exist.\n"); return; } break; - case COLOR_TEAM2: if(c2 == -1) { print("Sorry, can't move player to blue team if it doesn't exist.\n"); return; } break; - case COLOR_TEAM3: if(c3 == -1) { print("Sorry, can't move player to yellow team if it doesn't exist.\n"); return; } break; - case COLOR_TEAM4: if(c4 == -1) { print("Sorry, can't move player to pink team if it doesn't exist.\n"); return; } break; + case NUM_TEAM_1: if(c1 == -1) { print("Sorry, can't move player to red team if it doesn't exist.\n"); return; } break; + case NUM_TEAM_2: if(c2 == -1) { print("Sorry, can't move player to blue team if it doesn't exist.\n"); return; } break; + case NUM_TEAM_3: if(c3 == -1) { print("Sorry, can't move player to yellow team if it doesn't exist.\n"); return; } break; + case NUM_TEAM_4: if(c4 == -1) { print("Sorry, can't move player to pink team if it doesn't exist.\n"); return; } break; default: print("Sorry, can't move player here if team ", destination, " doesn't exist.\n"); return; } // If so, lets continue and finally move the player client.team_forced = 0; - MoveToTeam(client, team_color, 6, stof(notify)); + MoveToTeam(client, team_id, 6); successful = strcat(successful, (successful ? ", " : ""), client.netname); - print("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") has been moved to the ", ColoredTeamName(team_color), ".\n"); + print("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") has been moved to the ", Team_ColoredFullName(team_id), "^7.\n"); continue; } else @@ -1084,13 +1083,10 @@ void GameCommand_moveplayer(float request, float argc) print("Incorrect parameters for ^2moveplayer^7\n"); case CMD_REQUEST_USAGE: { - print("\nUsage:^3 sv_cmd moveplayer clients destination [notify]\n"); + print("\nUsage:^3 sv_cmd moveplayer clients destination\n"); print(" 'clients' is a list (separated by commas) of player entity ID's or nicknames\n"); print(" 'destination' is what to send the player to, be it team or spectating\n"); print(" Full list of destinations here: \"spec, spectator, red, blue, yellow, pink, auto.\"\n"); - print(" 'notify' is whether or not to send messages notifying of the move. Detail below.\n"); - print(" 0 (00) automove centerprint, admin message; 1 (01) automove centerprint, no admin message\n"); - print(" 2 (10) no centerprint, admin message; 3 (11) no centerprint, no admin message\n"); print("Examples: sv_cmd moveplayer 1,3,5 red 3\n"); print(" sv_cmd moveplayer 2 spec \n"); print("See also: ^2allspec, shuffleteams^7\n"); @@ -1112,7 +1108,7 @@ void GameCommand_nospectators(float request) if(plr.classname == "spectator" || plr.classname == "observer") { plr.spectatortime = time; - sprint(plr, strcat("^7You have to become a player within the next ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n")); + Send_Notification(NOTIF_ONE_ONLY, plr, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime); } } bprint(strcat("^7All spectators will be automatically kicked when not joining the game after ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds!\n")); @@ -1354,7 +1350,7 @@ void GameCommand_shuffleteams(float request) x = (t_players / t_teams); x = ((i == 1) ? ceil(x) : floor(x)); - team_color = NumberToTeamNumber(i); + team_color = Team_NumberToTeam(i); // sort through the random list of players made earlier for(z = 1; z <= maxclients; ++z) @@ -1368,7 +1364,7 @@ void GameCommand_shuffleteams(float request) self = edict_num(shuffleteams_players[z]); if(self.team != team_color) - MoveToTeam(self, team_color, 6, 0); + MoveToTeam(self, team_color, 6); shuffleteams_players[z] = 0; shuffleteams_teams[i] = shuffleteams_teams[i] + 1; @@ -1413,7 +1409,7 @@ void GameCommand_stuffto(float request, float argc) // This... is a fairly dangerous and powerful command... - It allows any arguments to be sent to a client via rcon. // Because of this, it is disabled by default and must be enabled by the server owner when doing compilation. That way, // we can be certain they understand the risks of it... So to enable, compile server with -DSTUFFTO_ENABLED argument. - + #ifdef STUFFTO_ENABLED #message "stuffto command enabled" switch(request) diff --git a/qcsrc/server/command/vote.qc b/qcsrc/server/command/vote.qc index 329fb9d4ef..e34464f16c 100644 --- a/qcsrc/server/command/vote.qc +++ b/qcsrc/server/command/vote.qc @@ -148,21 +148,21 @@ void VoteAccept() 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) @@ -319,6 +319,79 @@ void VoteThink() // 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); + + 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); + 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() { @@ -345,13 +418,13 @@ void ReadyRestart_force() 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)); } @@ -361,19 +434,19 @@ void ReadyRestart_force() 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; @@ -413,10 +486,13 @@ void ReadyCount() 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; @@ -610,7 +686,7 @@ float VoteCommand_parse(entity caller, string vote_command, string vote_list, fl 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") @@ -725,7 +801,7 @@ void VoteCommand_call(float request, entity caller, float argc, string vote_comm } 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)); } diff --git a/qcsrc/server/command/vote.qh b/qcsrc/server/command/vote.qh index 748b7ce6d9..1225b6be58 100644 --- a/qcsrc/server/command/vote.qh +++ b/qcsrc/server/command/vote.qh @@ -47,4 +47,5 @@ float readycount; // amount of players who are ready 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 diff --git a/qcsrc/server/constants.qh b/qcsrc/server/constants.qh index aec1e3256b..cb3c34fdc4 100644 --- a/qcsrc/server/constants.qh +++ b/qcsrc/server/constants.qh @@ -47,6 +47,9 @@ float DEAD_DEAD = 2; 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; @@ -106,6 +109,7 @@ float TE_KNIGHTSPIKE = 8; float TE_LIGHTNING3 = 9; float TE_LAVASPLASH = 10; float TE_TELEPORT = 11; +float TE_BEAM = 13; // grappling hook float UPDATE_GENERAL = 0; float UPDATE_STATIC = 1; @@ -139,14 +143,6 @@ float MSG_ENTITY = 5; // csqc //float POWERUP_INVINCIBLE_TAKEDAMAGE = 0.2; // received damage multiplier for invincible powerup - -float TE_BEAM = 13; // grappling hook - -float COLOR_TEAM1 = 5; // red -float COLOR_TEAM2 = 14; // blue -float COLOR_TEAM3 = 13; // yellow -float COLOR_TEAM4 = 10; // pink - float NUM_PLAYERSKINS_TEAMPLAY = 3; float ASSAULT_VALUE_INACTIVE = 1000; diff --git a/qcsrc/server/defs.qh b/qcsrc/server/defs.qh index 2f3eeaa4f3..95dbe48ff3 100644 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@ -39,7 +39,6 @@ float g_pickup_respawntimejitter_powerup; float g_jetpack; float sv_clones; -float sv_gentle; float sv_foginterval; entity activator; @@ -47,9 +46,6 @@ entity activator; 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; @@ -58,6 +54,9 @@ float team1_score, team2_score, team3_score, team4_score; float maxclients; +// flag set on worldspawn so that the code knows if it is dedicated or not +float server_is_dedicated; + // Fields .void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) event_damage; @@ -102,6 +101,7 @@ float maxclients; //.float cnt2; .float play_time; +.float respawn_flags; .float respawn_time; .float death_time; .float fade_time; @@ -206,8 +206,6 @@ float WS_READY = 4; // idle frame void weapon_defaultspawnfunc(float wpn); -string w_deathtypestring; - .vector dest1, dest2; float gameover; @@ -215,9 +213,6 @@ float intermission_running; float intermission_exittime; float alreadychangedlevel; - -.float runes; - // Keys player is holding .float itemkeys; // message delay for func_door locked by keys and key locks @@ -242,15 +237,12 @@ float game_completion_ratio; // 0 at start, 1 near end .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 lms_nextcheck; -.float lms_traveled_distance; - .entity flagcarried; .float playerid; @@ -284,9 +276,6 @@ float default_weapon_alpha; .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 @@ -297,9 +286,6 @@ string gamemode_name; float startitem_failed; -void DropAllRunes(entity pl); - - typedef .float floatfield; floatfield Item_CounterField(float it); @@ -455,8 +441,10 @@ string cvar_changes; 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; @@ -588,8 +576,6 @@ string deathmessage; .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 @@ -597,7 +583,6 @@ float serverflags; .float player_blocked; .float freezetag_frozen; -.float freezetag_revive_progress; .entity muzzle_flash; .float misc_bulletcounter; // replaces uzi & hlac bullet counter. diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index e779ff4535..fcabe6daf4 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -120,10 +120,6 @@ void GiveFrags (entity attacker, entity targ, float f, float deathtype) 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) { @@ -186,28 +182,6 @@ void GiveFrags (entity attacker, entity targ, float f, float deathtype) else { self = oldself; - if(g_runematch) - { - f = RunematchHandleFrags(attacker, targ, f); - } - else 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; @@ -216,44 +190,6 @@ void GiveFrags (entity attacker, entity targ, float f, float deathtype) UpdateFrags(attacker, f); } -string Obituary_ExtraFragInfo(entity player) // Extra fragmessage information -{ - string health_output = string_null; - string ping_output = string_null; - string handicap_output = string_null; - string output = string_null; - - if(autocvar_sv_fraginfo && ((autocvar_sv_fraginfo == 2) || inWarmupStage)) - { - // health/armor of attacker (person who killed you) - if(autocvar_sv_fraginfo_stats && (player.health >= 1)) - health_output = strcat("^7(Health ^1", ftos(rint(player.health)), "^7 / Armor ^2", ftos(rint(player.armorvalue)), "^7)"); - - // ping display - if(autocvar_sv_fraginfo_ping) - ping_output = ((clienttype(player) == CLIENTTYPE_BOT) ? "^2Bot" : strcat("Ping ", ((player.ping >= 150) ? "^1" : "^2"), ftos(rint(player.ping)), "ms")); - - // handicap display - if(autocvar_sv_fraginfo_handicap) - { - if(autocvar_sv_fraginfo_handicap == 2) - handicap_output = strcat(output, strcat("Handicap ^2", ((player.cvar_cl_handicap <= 1) ? "Off" : ftos(rint(player.cvar_cl_handicap))))); - else if(player.cvar_cl_handicap) // with _handicap 1, only show this if there actually is a handicap enabled. - handicap_output = strcat("Handicap ^2", ftos(rint(player.cvar_cl_handicap))); - } - - // format the string - output = strcat(health_output, (health_output ? ((ping_output || handicap_output) ? " ^7(" : "") : ((ping_output || handicap_output) ? "^7(" : "")), - ping_output, (handicap_output ? "^7 / " : ""), - handicap_output, ((ping_output || handicap_output) ? "^7)" : "")); - - // add new line to the beginning if there is a message - if(output) { output = strcat("\n", output); } - } - - return output; -} - string AppendItemcodes(string s, entity player) { float w; @@ -273,8 +209,6 @@ string AppendItemcodes(string s, entity player) s = strcat(s, "T"); if(player.kh_next) s = strcat(s, "K"); - if(player.runes) - s = strcat(s, "|", ftos(player.runes)); return s; } @@ -286,7 +220,7 @@ void LogDeath(string mode, float deathtype, entity killer, entity killed) s = strcat(":kill:", mode); s = strcat(s, ":", ftos(killer.playerid)); s = strcat(s, ":", ftos(killed.playerid)); - s = strcat(s, ":type=", ftos(deathtype)); + s = strcat(s, ":type=", Deathtype_Name(deathtype)); s = strcat(s, ":items="); s = AppendItemcodes(s, killer); if(killed != killer) @@ -297,225 +231,317 @@ void LogDeath(string mode, float deathtype, entity killer, entity killed) GameLogEcho(s); } -void Send_KillNotification (string s1, string s2, string s3, float msg, float type) +void Obituary_SpecialDeath( + entity notif_target, + float murder, + float deathtype, + string s1, string s2, string s3, + float f1, float f2, float f3) { - WriteByte(MSG_BROADCAST, SVC_TEMPENTITY); - WriteByte(MSG_BROADCAST, TE_CSQC_KILLNOTIFY); - WriteString(MSG_BROADCAST, s1); - WriteString(MSG_BROADCAST, s2); - WriteString(MSG_BROADCAST, s3); - WriteShort(MSG_BROADCAST, msg); - WriteByte(MSG_BROADCAST, type); + if(DEATH_ISSPECIAL(deathtype)) + { + entity deathent = deathtypes[(deathtype - DT_FIRST)]; + if not(deathent) { backtrace("Obituary_SpecialDeath: Could not find deathtype entity!\n"); return; } + + if(murder) + { + if(deathent.death_msgmurder) + { + Send_Notification_WOVA( + NOTIF_ONE, + notif_target, + MSG_MULTI, + deathent.death_msgmurder.nent_id, + s1, s2, s3, "", + f1, f2, f3, 0 + ); + Send_Notification_WOVA( + NOTIF_ALL_EXCEPT, + notif_target, + MSG_INFO, + deathent.death_msgmurder.nent_msginfo.nent_id, + s1, s2, s3, "", + f1, f2, f3, 0 + ); + } + } + else + { + if(deathent.death_msgself) + { + Send_Notification_WOVA( + NOTIF_ONE, + notif_target, + MSG_MULTI, + deathent.death_msgself.nent_id, + s1, s2, s3, "", + f1, f2, f3, 0 + ); + Send_Notification_WOVA( + NOTIF_ALL_EXCEPT, + notif_target, + MSG_INFO, + deathent.death_msgself.nent_msginfo.nent_id, + s1, s2, s3, "", + f1, f2, f3, 0 + ); + } + } + } + else { backtrace("Obituary_SpecialDeath called without a special deathtype?\n"); return; } } -// Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases) -void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type) +float w_deathtype; +float Obituary_WeaponDeath( + entity notif_target, + float murder, + float deathtype, + string s1, string s2, string s3, + float f1, float f2) { - if (clienttype(e) == CLIENTTYPE_REAL) + float death_weapon = DEATH_WEAPONOF(deathtype); + if(death_weapon) { - msg_entity = e; - WRITESPECTATABLE_MSG_ONE({ - WriteByte(MSG_ONE, SVC_TEMPENTITY); - WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT); - WriteString(MSG_ONE, s1); - WriteString(MSG_ONE, s2); - WriteShort(MSG_ONE, msg); - WriteByte(MSG_ONE, type); - }); + w_deathtype = deathtype; + float death_message = weapon_action(death_weapon, ((murder) ? WR_KILLMESSAGE : WR_SUICIDEMESSAGE)); + w_deathtype = FALSE; + + if(death_message) + { + Send_Notification_WOVA( + NOTIF_ONE, + notif_target, + MSG_MULTI, + death_message, + s1, s2, s3, "", + f1, f2, 0, 0 + ); + Send_Notification_WOVA( + NOTIF_ALL_EXCEPT, + notif_target, + MSG_INFO, + msg_multi_notifs[death_message - 1].nent_msginfo.nent_id, + s1, s2, s3, "", + f1, f2, 0, 0 + ); + } + else + { + dprint(sprintf( + "Obituary_WeaponDeath(): ^1Deathtype ^7(%d)^1 has no notification for weapon %d!\n", + deathtype, + death_weapon + )); + } + + return TRUE; } + return FALSE; } -void Obituary (entity attacker, entity inflictor, entity targ, float deathtype) +void Obituary(entity attacker, entity inflictor, entity targ, float deathtype) { - string s, a, msg; - float type; - - if (targ.classname == "player") + // Sanity check + if not(IS_PLAYER(targ)) { backtrace("Obituary called on non-player?!\n"); return; } + + // Declarations + float notif_firstblood = FALSE; + float kill_count_to_attacker, kill_count_to_target; + + // Set final information for the death + targ.death_origin = targ.origin; + if(targ != attacker) { targ.killer_origin = attacker.origin; } + string deathlocation = (autocvar_notification_server_allows_location ? NearestLocation(targ.death_origin) : ""); + + #ifdef NOTIFICATIONS_DEBUG + Debug_Notification( + sprintf( + "Obituary(%s, %s, %s, %s = %d);\n", + attacker.netname, + inflictor.netname, + targ.netname, + Deathtype_Name(deathtype), + deathtype + ) + ); + #endif + + // ======= + // SUICIDE + // ======= + if(targ == attacker) { - s = targ.netname; - a = attacker.netname; - - if (targ == attacker) // suicides + if(DEATH_ISSPECIAL(deathtype)) { - if (deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE) - msg = ColoredTeamName(targ.team); // TODO: check if needed? - else - msg = ""; - if(!g_cts) // no "killed your own dumb self" message in CTS - Send_CSQC_KillCenterprint(targ, msg, "", deathtype, MSG_SUICIDE); - - if(deathtype != DEATH_TEAMCHANGE && deathtype != DEATH_QUIET) + if(deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE) { - LogDeath("suicide", deathtype, targ, targ); - GiveFrags(attacker, targ, -1, deathtype); + Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.team, 0, 0); } - - if (targ.killcount > 2) - msg = ftos(targ.killcount); else - msg = ""; - if(teamplay && deathtype == DEATH_MIRRORDAMAGE) { - if(attacker.team == COLOR_TEAM1) - deathtype = KILL_TEAM_RED; - else - deathtype = KILL_TEAM_BLUE; + switch(deathtype) + { + case DEATH_MIRRORDAMAGE: + { + Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0, 0); + break; + } + + default: + { + Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0, 0); + break; + } + } } - - Send_KillNotification(s, msg, "", deathtype, MSG_SUICIDE); } - else if (attacker.classname == "player") + else if not(Obituary_WeaponDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0)) { - if(!IsDifferentTeam(attacker, targ)) - { - if(attacker.team == COLOR_TEAM1) - type = KILL_TEAM_RED; - else - type = KILL_TEAM_BLUE; - - GiveFrags(attacker, targ, -1, deathtype); + backtrace("SUICIDE: what the hell happened here?\n"); + return; + } + LogDeath("suicide", deathtype, targ, targ); + GiveFrags(attacker, targ, -1, deathtype); + } - Send_CSQC_KillCenterprint(attacker, s, "", type, MSG_KILL); + // ====== + // MURDER + // ====== + else if(IS_PLAYER(attacker)) + { + if(!IsDifferentTeam(attacker, targ)) + { + LogDeath("tk", deathtype, attacker, targ); + GiveFrags(attacker, targ, -1, deathtype); - if (targ.killcount > 2) - msg = ftos(targ.killcount); - else - msg = ""; + attacker.killcount = 0; + + 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, deathlocation, targ.killcount); - if (attacker.killcount > 2) { - msg = ftos(attacker.killcount); - type = KILL_TEAM_SPREE; + // In this case, the death message will ALWAYS be "foo was betrayed by bar" + // No need for specific death/weapon messages... + } + else + { + LogDeath("frag", deathtype, attacker, targ); + GiveFrags(attacker, targ, 1, deathtype); + + attacker.taunt_soundtime = time + 1; + attacker.killcount = attacker.killcount + 1; + + #define SPREE_ITEM(counta,countb,center,normal,gentle) \ + case counta: \ + { \ + Send_Notification(NOTIF_ONE, attacker, MSG_ANNCE, ANNCE_KILLSTREAK_##countb); \ + PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \ + break; \ } - Send_KillNotification(a, s, msg, type, MSG_KILL); - - attacker.killcount = 0; + switch(attacker.killcount) + { + KILL_SPREE_LIST + default: break; + } + #undef SPREE_ITEM - LogDeath("tk", deathtype, attacker, targ); + if(!checkrules_firstblood) + { + checkrules_firstblood = TRUE; + notif_firstblood = TRUE; // modify the current messages so that they too show firstblood information + PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1); + PlayerStats_Event(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1); + + // tell spree_inf and spree_cen that this is a first-blood and first-victim event + kill_count_to_attacker = -1; + kill_count_to_target = -2; } else { - if (!checkrules_firstblood) - { - checkrules_firstblood = TRUE; - Send_KillNotification(a, "", "", KILL_FIRST_BLOOD, MSG_KILL); - // TODO: make these print a newline if they dont - Send_CSQC_KillCenterprint(attacker, "", "", KILL_FIRST_BLOOD, MSG_KILL); - Send_CSQC_KillCenterprint(targ, "", "", KILL_FIRST_VICTIM, MSG_KILL); - PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1); - PlayerStats_Event(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1); - } - - if(targ.istypefrag) { - Send_CSQC_KillCenterprint(attacker, s, Obituary_ExtraFragInfo(targ), KILL_TYPEFRAG, MSG_KILL); - Send_CSQC_KillCenterprint(targ, a, Obituary_ExtraFragInfo(attacker), KILL_TYPEFRAGGED, MSG_KILL); - } else { - Send_CSQC_KillCenterprint(attacker, s, Obituary_ExtraFragInfo(targ), KILL_FRAG, MSG_KILL); - Send_CSQC_KillCenterprint(targ, a, Obituary_ExtraFragInfo(attacker), KILL_FRAGGED, MSG_KILL); - } - - attacker.taunt_soundtime = time + 1; + kill_count_to_attacker = attacker.killcount; + kill_count_to_target = 0; + } - if (deathtype == DEATH_HURTTRIGGER && inflictor.message2 != "") - msg = inflictor.message2; - else if (deathtype == DEATH_CUSTOM) - msg = deathmessage; + float verbose_allowed = (autocvar_notification_server_allows_frag_verbose && ((autocvar_notification_server_allows_frag_verbose == 2) || inWarmupStage)); + if(targ.istypefrag) + { + if(attacker.FRAG_VERBOSE && verbose_allowed) + Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE, targ.netname, kill_count_to_attacker, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping)); else - msg = ""; + Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAG, targ.netname, kill_count_to_attacker); - if(strstrofs(msg, "%", 0) < 0) - msg = strcat("%s ", msg, " by %s"); - - Send_KillNotification(a, s, msg, deathtype, MSG_KILL); + if(targ.FRAG_VERBOSE && verbose_allowed) + Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE, attacker.netname, kill_count_to_target, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping)); + else + Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAGGED, attacker.netname, kill_count_to_target); + } + else + { + if(attacker.FRAG_VERBOSE && verbose_allowed) + Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_FRAG_VERBOSE, targ.netname, kill_count_to_attacker, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping)); + else + Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_FRAG, targ.netname, kill_count_to_attacker); - GiveFrags(attacker, targ, 1, deathtype); + if(targ.FRAG_VERBOSE && verbose_allowed) + Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_FRAGGED_VERBOSE, attacker.netname, kill_count_to_target, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping)); + else + Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_FRAGGED, attacker.netname, kill_count_to_target); + } - if (targ.killcount > 2) { - Send_KillNotification(s, ftos(targ.killcount), a, KILL_END_SPREE, MSG_SPREE); - } + if not(Obituary_WeaponDeath(targ, TRUE, deathtype, targ.netname, attacker.netname, deathlocation, targ.killcount, kill_count_to_attacker)) + Obituary_SpecialDeath(targ, TRUE, deathtype, targ.netname, attacker.netname, deathlocation, targ.killcount, kill_count_to_attacker, 0); + } + } - attacker.killcount = attacker.killcount + 1; + // ============= + // ACCIDENT/TRAP + // ============= + else + { + switch(deathtype) + { + // For now, we're just forcing HURTTRIGGER to behave as "DEATH_VOID" and giving it no special options... + // Later on you will only be able to make custom messages using DEATH_CUSTOM, + // and there will be a REAL DEATH_VOID implementation which mappers will use. + /*case DEATH_HURTTRIGGER: + { + s1 = targ.netname; + s2 = inflictor.message; + if(strstrofs(s2, "%", 0) < 0) { s2 = strcat("%s ", s2); } + break; + }*/ - if (attacker.killcount == 3) - { - Send_KillNotification(a, "", "", KILL_SPREE_3, MSG_SPREE); - AnnounceTo(attacker, "03kills"); - PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_3, 1); - } - else if (attacker.killcount == 5) - { - Send_KillNotification(a, "", "", KILL_SPREE_5, MSG_SPREE); - AnnounceTo(attacker, "05kills"); - PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_5, 1); - } - else if (attacker.killcount == 10) - { - Send_KillNotification(a, "", "", KILL_SPREE_10, MSG_SPREE); - AnnounceTo(attacker, "10kills"); - PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_10, 1); - } - else if (attacker.killcount == 15) - { - Send_KillNotification(a, "", "", KILL_SPREE_15, MSG_SPREE); - AnnounceTo(attacker, "15kills"); - PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_15, 1); - } - else if (attacker.killcount == 20) - { - Send_KillNotification(a, "", "", KILL_SPREE_20, MSG_SPREE); - AnnounceTo(attacker, "20kills"); - PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_20, 1); - } - else if (attacker.killcount == 25) - { - Send_KillNotification(a, "", "", KILL_SPREE_25, MSG_SPREE); - AnnounceTo(attacker, "25kills"); - PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_25, 1); - } - else if (attacker.killcount == 30) - { - Send_KillNotification(a, "", "", KILL_SPREE_30, MSG_SPREE); - AnnounceTo(attacker, "30kills"); - PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_30, 1); - } - else if (attacker.killcount > 2) { - Send_KillNotification(a, ftos(attacker.killcount), "", KILL_SPREE, MSG_SPREE); - } - LogDeath("frag", deathtype, attacker, targ); + case DEATH_CUSTOM: + { + Obituary_SpecialDeath(targ, FALSE, deathtype, + targ.netname, + ((strstrofs(deathmessage, "%", 0) < 0) ? strcat("%s ", deathmessage) : deathmessage), + deathlocation, + targ.killcount, + 0, + 0); + break; } - } - else - { - Send_CSQC_KillCenterprint(targ, "", "", deathtype, MSG_KILL_ACTION); - if (deathtype == DEATH_HURTTRIGGER && inflictor.message != "") - msg = inflictor.message; - else if (deathtype == DEATH_CUSTOM) - msg = deathmessage; - else - msg = ""; - if(strstrofs(msg, "%", 0) < 0) - msg = strcat("%s ", msg); - - GiveFrags(targ, targ, -1, deathtype); - if(PlayerScore_Add(targ, SP_SCORE, 0) == -5) { - AnnounceTo(targ, "botlike"); - PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1); + + default: + { + Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0, 0); + break; } - Send_KillNotification(s, msg, "", deathtype, MSG_KILL_ACTION); - - if (targ.killcount > 2) - Send_KillNotification(s, ftos(targ.killcount), "", 0, MSG_KILL_ACTION_SPREE); - - LogDeath("accident", deathtype, targ, targ); } - targ.death_origin = targ.origin; - if(targ != attacker) - targ.killer_origin = attacker.origin; + LogDeath("accident", deathtype, targ, targ); + GiveFrags(targ, targ, -1, deathtype); - // FIXME: this should go in PutClientInServer - if (targ.killcount) - targ.killcount = 0; + if(PlayerScore_Add(targ, SP_SCORE, 0) == -5) + { + Send_Notification(NOTIF_ONE, targ, MSG_ANNCE, ANNCE_ACHIEVEMENT_BOTLIKE); + PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1); + } } + + // reset target kill count + if(targ.killcount) { targ.killcount = 0; } } // these are updated by each Damage call for use in button triggering and such @@ -560,7 +586,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float } } - if(deathtype == DEATH_KILL || deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE || deathtype == DEATH_QUIET) + if(deathtype == DEATH_KILL || deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE) { // These are ALWAYS lethal // No damage modification here @@ -651,14 +677,6 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float } } - 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) { @@ -743,40 +761,6 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself } - if(g_runematch) - { - // apply strength rune - if (attacker.runes & RUNE_STRENGTH) - { - if(attacker.runes & CURSE_WEAK) // have both curse & rune - { - damage = damage * autocvar_g_balance_rune_strength_combo_damage; - force = force * autocvar_g_balance_rune_strength_combo_force; - } - else - { - damage = damage * autocvar_g_balance_rune_strength_damage; - force = force * autocvar_g_balance_rune_strength_force; - } - } - else if (attacker.runes & CURSE_WEAK) - { - damage = damage * autocvar_g_balance_curse_weak_damage; - force = force * autocvar_g_balance_curse_weak_force; - } - - // apply defense rune - if (targ.runes & RUNE_DEFENSE) - { - if (targ.runes & CURSE_VULNER) // have both curse & rune - damage = damage * autocvar_g_balance_rune_defense_combo_takedamage; - else - damage = damage * autocvar_g_balance_rune_defense_takedamage; - } - else if (targ.runes & CURSE_VULNER) - damage = damage * autocvar_g_balance_curse_vulner_takedamage; - } - // count the damage if(attacker) if(!targ.deadflag) @@ -868,42 +852,6 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float self.event_damage (inflictor, attacker, damage, deathtype, hitloc, force); self = oldself; - if(targ.classname == "player" && attacker.classname == "player" && attacker != targ && attacker.health > 2) - { - if(g_runematch) - { - if (attacker.runes & RUNE_VAMPIRE) - { - // apply vampire rune - if (attacker.runes & CURSE_EMPATHY) // have the curse too - { - //attacker.health = attacker.health + damage * autocvar_g_balance_rune_vampire_combo_absorb; - attacker.health = bound( - autocvar_g_balance_curse_empathy_minhealth, // LA: was 3, now 40 - attacker.health + damage * autocvar_g_balance_rune_vampire_combo_absorb, - autocvar_g_balance_rune_vampire_maxhealth); // LA: was 1000, now 500 - } - else - { - //attacker.health = attacker.health + damage * autocvar_g_balance_rune_vampire_absorb; - attacker.health = bound( - attacker.health, // LA: was 3, but changed so that you can't lose health - // empathy won't let you gain health in the same way... - attacker.health + damage * autocvar_g_balance_rune_vampire_absorb, - autocvar_g_balance_rune_vampire_maxhealth); // LA: was 1000, now 500 - } - } - // apply empathy curse - else if (attacker.runes & CURSE_EMPATHY) - { - attacker.health = bound( - autocvar_g_balance_curse_empathy_minhealth, // LA: was 3, now 20 - attacker.health + damage * autocvar_g_balance_curse_empathy_takedamage, - attacker.health); - } - } - } - // apply mirror damage if any if(mirrordamage > 0 || mirrorforce > 0) { diff --git a/qcsrc/server/g_hook.qc b/qcsrc/server/g_hook.qc index f7af47d924..dec6e167d1 100644 --- a/qcsrc/server/g_hook.qc +++ b/qcsrc/server/g_hook.qc @@ -121,7 +121,7 @@ void GrapplingHookThink() 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; @@ -299,14 +299,8 @@ void FireGrapplingHook (void) 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); diff --git a/qcsrc/server/g_triggers.qc b/qcsrc/server/g_triggers.qc index 293c78f001..12c75ae9e5 100644 --- a/qcsrc/server/g_triggers.qc +++ b/qcsrc/server/g_triggers.qc @@ -476,17 +476,6 @@ void trigger_hurt_touch() Damage(other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0'); } } - else - { - if (!other.owner) - { - if (other.classname == "rune") // reset runes - { - EXACTTRIGGER_TOUCH; - other.nextthink = min(other.nextthink, time + 1); - } - } - } return; } diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index d67ef26eba..1af52b1320 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -256,22 +256,22 @@ void cvar_changes_init() 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_race"); BADCVAR("g_race_qualifying_timelimit"); - BADCVAR("g_runematch"); BADCVAR("g_tdm"); BADCVAR("g_tdm_teams"); BADCVAR("leadlimit"); @@ -315,7 +315,6 @@ void cvar_changes_init() BADCVAR("g_keyhunt_point_leadlimit"); BADPREFIX("g_mod_"); BADCVAR("g_nexball_goalleadlimit"); - BADCVAR("g_runematch_point_leadlimit"); BADCVAR("leadlimit_and_fraglimit"); BADCVAR("leadlimit_override"); BADCVAR("pausable"); @@ -361,8 +360,10 @@ void cvar_changes_init() 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"); @@ -381,7 +382,6 @@ void cvar_changes_init() BADCVAR("g_mirrordamage"); BADCVAR("g_nexball_goallimit"); BADCVAR("g_powerups"); - BADCVAR("g_runematch_point_limit"); BADCVAR("g_start_delay"); BADCVAR("g_warmup"); BADCVAR("g_weapon_stay"); BADPRESUFFIX("g_", "_weapon_stay"); @@ -550,6 +550,8 @@ void spawnfunc___init_dedicated_server(void) // needs to be done so early because of the constants they create CALL_ACCUMULATED_FUNCTION(RegisterWeapons); CALL_ACCUMULATED_FUNCTION(RegisterGametypes); + CALL_ACCUMULATED_FUNCTION(RegisterNotifications); + CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); MapInfo_Enumerate(); MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0); @@ -582,8 +584,6 @@ void spawnfunc_worldspawn (void) compressShortVector_init(); - allowed_to_spawn = TRUE; - entity head; head = nextent(world); maxclients = 0; @@ -593,9 +593,13 @@ void spawnfunc_worldspawn (void) head = nextent(head); } + server_is_dedicated = (stof(cvar_defstring("is_dedicated")) ? TRUE : FALSE); + // needs to be done so early because of the constants they create CALL_ACCUMULATED_FUNCTION(RegisterWeapons); CALL_ACCUMULATED_FUNCTION(RegisterGametypes); + CALL_ACCUMULATED_FUNCTION(RegisterNotifications); + CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid)); @@ -780,6 +784,7 @@ void spawnfunc_worldspawn (void) 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(); @@ -802,19 +807,6 @@ void spawnfunc_worldspawn (void) 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); @@ -1347,7 +1339,7 @@ void IntermissionThink() && ((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; } @@ -1475,7 +1467,7 @@ void DumpStats(float final) { 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:"); @@ -1589,6 +1581,8 @@ void NextLevel() PlayerStats_AddGlobalInfo(e); PlayerStats_Shutdown(); WeaponStats_Shutdown(); + + Kill_Notification(NOTIF_ALL, world, MSG_CENTER, 0); // kill all centerprints now if(autocvar_sv_eventlog) GameLogEcho(":gameover"); @@ -1672,20 +1666,8 @@ void InitiateOvertime() // ONLY call this if InitiateSuddenDeath returned true tl = autocvar_timelimit; tl += autocvar_timelimit_overtime; cvar_set("timelimit", ftos(tl)); - string minutesPlural; - if (autocvar_timelimit_overtime == 1) - minutesPlural = " ^3minute"; - else - minutesPlural = " ^3minutes"; - - bcenterprint( - strcat( - "^3Now playing ^1OVERTIME^3!\n\n^3Added ^1", - ftos(autocvar_timelimit_overtime), - minutesPlural, - " to the game!" - ) - ); + + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime * 60); } float GetWinningCode(float fraglimitreached, float equality) @@ -1753,10 +1735,10 @@ float WinningCondition_Onslaught() { if (head.health > 0) { - if (head.team == COLOR_TEAM1) t1 = 1; - if (head.team == COLOR_TEAM2) t2 = 1; - if (head.team == COLOR_TEAM3) t3 = 1; - if (head.team == COLOR_TEAM4) t4 = 1; + if (head.team == NUM_TEAM_1) t1 = 1; + if (head.team == NUM_TEAM_2) t2 = 1; + if (head.team == NUM_TEAM_3) t3 = 1; + if (head.team == NUM_TEAM_4) t4 = 1; } head = find(head, classname, "onslaught_generator"); } @@ -1764,10 +1746,10 @@ float WinningCondition_Onslaught() { // game over, only one team remains (or none) ClearWinners(); - if (t1) SetWinners(team, COLOR_TEAM1); - if (t2) SetWinners(team, COLOR_TEAM2); - if (t3) SetWinners(team, COLOR_TEAM3); - if (t4) SetWinners(team, COLOR_TEAM4); + if (t1) SetWinners(team, NUM_TEAM_1); + if (t2) SetWinners(team, NUM_TEAM_2); + if (t3) SetWinners(team, NUM_TEAM_3); + if (t4) SetWinners(team, NUM_TEAM_4); dprint("Have a winner, ending game.\n"); return WINNING_YES; } @@ -1776,24 +1758,6 @@ float WinningCondition_Onslaught() 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(); @@ -1805,13 +1769,13 @@ float WinningCondition_Assault() status = WINNING_NO; // as the timelimit has not yet passed just assume the defending team will win - if(assault_attacker_team == COLOR_TEAM1) + if(assault_attacker_team == NUM_TEAM_1) { - SetWinners(team, COLOR_TEAM2); + SetWinners(team, NUM_TEAM_2); } else { - SetWinners(team, COLOR_TEAM1); + SetWinners(team, NUM_TEAM_1); } entity ent; @@ -1937,10 +1901,10 @@ float WinningCondition_Scores(float limit, float leadlimit) if(teamplay) { - team1_score = TeamScore_GetCompareValue(COLOR_TEAM1); - team2_score = TeamScore_GetCompareValue(COLOR_TEAM2); - team3_score = TeamScore_GetCompareValue(COLOR_TEAM3); - team4_score = TeamScore_GetCompareValue(COLOR_TEAM4); + team1_score = TeamScore_GetCompareValue(NUM_TEAM_1); + team2_score = TeamScore_GetCompareValue(NUM_TEAM_2); + team3_score = TeamScore_GetCompareValue(NUM_TEAM_3); + team4_score = TeamScore_GetCompareValue(NUM_TEAM_4); } ClearWinners(); @@ -1968,11 +1932,11 @@ float WinningCondition_Scores(float limit, float leadlimit) 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); } } @@ -2056,25 +2020,25 @@ float WinningCondition_RanOutOfSpawns() FOR_EACH_PLAYER(head) if(head.deadflag == DEAD_NO) { - if(head.team == COLOR_TEAM1) + if(head.team == NUM_TEAM_1) team1_score = 1; - else if(head.team == COLOR_TEAM2) + else if(head.team == NUM_TEAM_2) team2_score = 1; - else if(head.team == COLOR_TEAM3) + else if(head.team == NUM_TEAM_3) team3_score = 1; - else if(head.team == COLOR_TEAM4) + else if(head.team == NUM_TEAM_4) team4_score = 1; } for(head = world; (head = find(head, classname, "info_player_deathmatch")) != world; ) { - if(head.team == COLOR_TEAM1) + if(head.team == NUM_TEAM_1) team1_score = 1; - else if(head.team == COLOR_TEAM2) + else if(head.team == NUM_TEAM_2) team2_score = 1; - else if(head.team == COLOR_TEAM3) + else if(head.team == NUM_TEAM_3) team3_score = 1; - else if(head.team == COLOR_TEAM4) + else if(head.team == NUM_TEAM_4) team4_score = 1; } @@ -2088,20 +2052,20 @@ float WinningCondition_RanOutOfSpawns() { float t, i; if(team1_score) - t = COLOR_TEAM1; + t = NUM_TEAM_1; else if(team2_score) - t = COLOR_TEAM2; + t = NUM_TEAM_2; else if(team3_score) - t = COLOR_TEAM3; + t = NUM_TEAM_3; else // if(team4_score) - t = COLOR_TEAM4; + t = NUM_TEAM_4; CheckAllowedTeams(world); for(i = 0; i < MAX_TEAMSCORE; ++i) { - if(t != COLOR_TEAM1) if(c1 >= 0) TeamScore_AddToTeam(COLOR_TEAM1, i, -1000); - if(t != COLOR_TEAM2) if(c2 >= 0) TeamScore_AddToTeam(COLOR_TEAM2, i, -1000); - if(t != COLOR_TEAM3) if(c3 >= 0) TeamScore_AddToTeam(COLOR_TEAM3, i, -1000); - if(t != COLOR_TEAM4) if(c4 >= 0) TeamScore_AddToTeam(COLOR_TEAM4, i, -1000); + if(t != NUM_TEAM_1) if(c1 >= 0) TeamScore_AddToTeam(NUM_TEAM_1, i, -1000); + if(t != NUM_TEAM_2) if(c2 >= 0) TeamScore_AddToTeam(NUM_TEAM_2, i, -1000); + if(t != NUM_TEAM_3) if(c3 >= 0) TeamScore_AddToTeam(NUM_TEAM_3, i, -1000); + if(t != NUM_TEAM_4) if(c4 >= 0) TeamScore_AddToTeam(NUM_TEAM_4, i, -1000); } AddWinners(team, t); @@ -2191,9 +2155,9 @@ void CheckRules_World() { checkrules_suddendeathwarning = TRUE; if(g_race && !g_race_qualifying) - bcenterprint("^3Everyone, finish your lap! The race is over!"); + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_RACE_FINISHLAP); else - bcenterprint("^3Now playing ^1OVERTIME^3!\n\n^3Keep fragging until we have a ^1winner^3!"); + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_FRAG); } } else diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index e3689cc3d3..191bfaede1 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -32,7 +32,6 @@ void WarpZone_crosshair_trace(entity pl) void() spawnfunc_info_player_deathmatch; // needed for the other spawnpoints void() spawnpoint_use; string GetMapname(); -string ColoredTeamName(float t); string admin_name(void) { @@ -80,26 +79,27 @@ float DistributeEvenly_GetRandomized(float weight) #define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e) - string STR_PLAYER = "player"; string STR_SPECTATOR = "spectator"; string STR_OBSERVER = "observer"; -#if 0 -#define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; ) -#define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL) -#define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; ) -#define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL) -#else +#define IS_PLAYER(v) (v.classname == STR_PLAYER) +#define IS_SPEC(v) (v.classname == STR_SPECTATOR) +#define IS_OBSERVER(v) (v.classname == STR_OBSERVER) +#define IS_CLIENT(v) (v.flags & FL_CLIENT) +#define IS_BOT_CLIENT(v) (clienttype(v) == CLIENTTYPE_BOT) +#define IS_REAL_CLIENT(v) (clienttype(v) == CLIENTTYPE_REAL) +#define IS_NOT_A_CLIENT(v) (clienttype(v) == CLIENTTYPE_NOTACLIENT) + #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); ) -#define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT) -#define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL) -#define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER) -#define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if(v.classname != STR_PLAYER) -#define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER) -#endif +#define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(IS_CLIENT(v)) +#define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(IS_REAL_CLIENT(v)) -#define CENTER_OR_VIEWOFS(ent) (ent.origin + ((ent.classname == STR_PLAYER) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5))) +#define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(IS_PLAYER(v)) +#define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if not(IS_PLAYER(v)) // Samual: shouldn't this be IS_SPEC(v)? and rather create a separate macro to include observers too +#define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(IS_PLAYER(v)) + +#define CENTER_OR_VIEWOFS(ent) (ent.origin + (IS_PLAYER(ent) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5))) // copies a string to a tempstring (so one can strunzone it) string strcat1(string s) = #115; // FRIK_FILE @@ -107,15 +107,6 @@ string strcat1(string s) = #115; // FRIK_FILE float logfile_open; float logfile; -void bcenterprint(string s) -{ - // TODO replace by MSG_ALL (would show it to spectators too, though)? - entity head; - FOR_EACH_PLAYER(head) - if (clienttype(head) == CLIENTTYPE_REAL) - centerprint(head, s); -} - void GameLogEcho(string s) { string fn; @@ -546,7 +537,11 @@ void GetCvars(float f) get_cvars_f = f; get_cvars_s = s; + MUTATOR_CALLHOOK(GetCvars); + + Notification_GetCvars(); + GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch"); GetCvars_handleFloat(s, f, cvar_cl_autoscreenshot, "cl_autoscreenshot"); GetCvars_handleString(s, f, cvar_g_xonoticversion, "g_xonoticversion"); @@ -590,102 +585,6 @@ void GetCvars(float f) } } -void backtrace(string msg) -{ - float dev, war; - dev = autocvar_developer; - war = autocvar_prvm_backtraceforwarnings; - cvar_set("developer", "1"); - cvar_set("prvm_backtraceforwarnings", "1"); - print("\n"); - print("--- CUT HERE ---\nWARNING: "); - print(msg); - print("\n"); - remove(world); // isn't there any better way to cause a backtrace? - print("\n--- CUT UNTIL HERE ---\n"); - cvar_set("developer", ftos(dev)); - cvar_set("prvm_backtraceforwarnings", ftos(war)); -} - -string Team_ColorCode(float teamid) -{ - if (teamid == COLOR_TEAM1) - return "^1"; - else if (teamid == COLOR_TEAM2) - return "^4"; - else if (teamid == COLOR_TEAM3) - return "^3"; - else if (teamid == COLOR_TEAM4) - return "^6"; - else - return "^7"; -} - -string Team_ColorName(float t) -{ - // fixme: Search for team entities and get their .netname's! - if (t == COLOR_TEAM1) - return "Red"; - if (t == COLOR_TEAM2) - return "Blue"; - if (t == COLOR_TEAM3) - return "Yellow"; - if (t == COLOR_TEAM4) - return "Pink"; - return "Neutral"; -} - -string Team_ColorNameLowerCase(float t) -{ - // fixme: Search for team entities and get their .netname's! - if (t == COLOR_TEAM1) - return "red"; - if (t == COLOR_TEAM2) - return "blue"; - if (t == COLOR_TEAM3) - return "yellow"; - if (t == COLOR_TEAM4) - return "pink"; - return "neutral"; -} - -float ColourToNumber(string team_colour) -{ - if (team_colour == "red") - return COLOR_TEAM1; - - if (team_colour == "blue") - return COLOR_TEAM2; - - if (team_colour == "yellow") - return COLOR_TEAM3; - - if (team_colour == "pink") - return COLOR_TEAM4; - - if (team_colour == "auto") - return 0; - - return -1; -} - -float NumberToTeamNumber(float number) -{ - if (number == 1) - return COLOR_TEAM1; - - if (number == 2) - return COLOR_TEAM2; - - if (number == 3) - return COLOR_TEAM3; - - if (number == 4) - return COLOR_TEAM4; - - return -1; -} - // decolorizes and team colors the player name when needed string playername(entity p) { @@ -851,7 +750,7 @@ void readplayerstartcvars() s = cvar_string("g_weaponarena"); if (s == "0" || s == "") { - if(g_lms || g_ca) + if(g_ca) s = "most"; } @@ -929,8 +828,7 @@ void readplayerstartcvars() g_pinata = 0; // incompatible g_weapon_stay = 0; // incompatible WEPSET_COPY_AA(start_weapons, g_weaponarena_weapons); - if(!(g_lms || g_ca)) - start_items |= IT_UNLIMITED_AMMO; + start_items |= IT_UNLIMITED_AMMO; } else if (g_minstagib) { @@ -982,28 +880,11 @@ void readplayerstartcvars() } else { - if(g_lms || g_ca) - { - 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"); - } - else - { - start_ammo_shells = cvar("g_start_ammo_shells"); - start_ammo_nails = cvar("g_start_ammo_nails"); - start_ammo_rockets = cvar("g_start_ammo_rockets"); - start_ammo_cells = cvar("g_start_ammo_cells"); - start_ammo_fuel = cvar("g_start_ammo_fuel"); - } - } - - if (g_lms || g_ca) - { - start_health = cvar("g_lms_start_health"); - start_armorvalue = cvar("g_lms_start_armor"); + start_ammo_shells = cvar("g_start_ammo_shells"); + start_ammo_nails = cvar("g_start_ammo_nails"); + start_ammo_rockets = cvar("g_start_ammo_rockets"); + start_ammo_cells = cvar("g_start_ammo_cells"); + start_ammo_fuel = cvar("g_start_ammo_fuel"); } if (inWarmupStage) @@ -1094,12 +975,6 @@ float g_bugrigs_speed_ref; 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; @@ -1115,6 +990,8 @@ void readlevelcvars(void) 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")) @@ -1154,14 +1031,7 @@ void readlevelcvars(void) 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_gentle = cvar("sv_gentle"); sv_foginterval = cvar("sv_foginterval"); g_cloaked = cvar("g_cloaked"); if(g_cts) @@ -1183,7 +1053,7 @@ void readlevelcvars(void) g_warmup_allguns = cvar("g_warmup_allguns"); g_warmup_allow_timeout = cvar("g_warmup_allow_timeout"); - if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign")) + if ((g_race && g_race_qualifying == 2) || g_arena || g_assault || cvar("g_campaign")) inWarmupStage = 0; // these modes cannot work together, sorry g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon"); @@ -1252,8 +1122,8 @@ void readlevelcvars(void) 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(); } @@ -1516,11 +1386,6 @@ void precache() { // gamemode related things precache_model ("models/misc/chatbubble.spr"); - if (g_runematch) - { - precache_model ("models/runematch/curse.mdl"); - precache_model ("models/runematch/rune.mdl"); - } #ifdef TTURRETS_ENABLED if (autocvar_g_turrets) @@ -1640,34 +1505,6 @@ void precache() #endif } -// sorry, but using \ in macros breaks line numbers -#define WRITESPECTATABLE_MSG_ONE_VARNAME(varname,statement) entity varname; varname = msg_entity; FOR_EACH_REALCLIENT(msg_entity) if(msg_entity == varname || (msg_entity.classname == STR_SPECTATOR && msg_entity.enemy == varname)) statement msg_entity = varname -#define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement) -#define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0 - - -void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num) -{ - if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT)) - { - msg_entity = e; - WRITESPECTATABLE_MSG_ONE({ - WriteByte(MSG_ONE, SVC_TEMPENTITY); - WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC); - WriteByte(MSG_ONE, id); - WriteString(MSG_ONE, s); - if (id != 0 && s != "") - { - WriteByte(MSG_ONE, duration); - WriteByte(MSG_ONE, countdown_num); - } - }); - } -} -void Send_CSQC_Centerprint_Generic_Expire(entity e, float id) -{ - Send_CSQC_Centerprint_Generic(e, id, "", 1, 0); -} // WARNING: this kills the trace globals #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init() @@ -2146,22 +1983,6 @@ string race_readName(string map, float pos) return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)))); } -string race_placeName(float pos) { - if(floor((mod(pos, 100))/10) * 10 != 10) // examples: 12th, 111th, 213th will not execute this block - { - if(mod(pos, 10) == 1) - return strcat(ftos(pos), "st"); - else if(mod(pos, 10) == 2) - return strcat(ftos(pos), "nd"); - else if(mod(pos, 10) == 3) - return strcat(ftos(pos), "rd"); - else - return strcat(ftos(pos), "th"); - } - else - return strcat(ftos(pos), "th"); -} - float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance) { float m, i; diff --git a/qcsrc/server/mutators/base.qh b/qcsrc/server/mutators/base.qh index d90d564b50..311d156304 100644 --- a/qcsrc/server/mutators/base.qh +++ b/qcsrc/server/mutators/base.qh @@ -46,10 +46,22 @@ void Mutator_Remove(mutatorfunc_t func, string name); // calls error() on fail 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 @@ -59,6 +71,7 @@ MUTATOR_HOOKABLE(PlayerDies); 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 @@ -142,7 +155,7 @@ MUTATOR_HOOKABLE(PlayerDamage_SplitHealthArmor); float damage_save; MUTATOR_HOOKABLE(PlayerDamage_Calculate); - // called to adjust damage and force values which are applied to the player, used for e.g. strength damage/force multiplier or runematch runes + // called to adjust damage and force values which are applied to the player, used for e.g. strength damage/force multiplier // i'm not sure if I should change this around slightly (Naming of the entities, and also how they're done in g_damage). // INPUT: entity frag_attacker; @@ -235,6 +248,10 @@ MUTATOR_HOOKABLE(HelpMePing); // 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 diff --git a/qcsrc/server/mutators/gamemode_arena.qc b/qcsrc/server/mutators/gamemode_arena.qc new file mode 100644 index 0000000000..46b8faccc1 --- /dev/null +++ b/qcsrc/server/mutators/gamemode_arena.qc @@ -0,0 +1,278 @@ +.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; +} diff --git a/qcsrc/server/mutators/gamemode_arena.qh b/qcsrc/server/mutators/gamemode_arena.qh new file mode 100644 index 0000000000..a2f623a000 --- /dev/null +++ b/qcsrc/server/mutators/gamemode_arena.qh @@ -0,0 +1,2 @@ +// should be removed in the future, as other code should not have to care +float arena_roundbased; diff --git a/qcsrc/server/mutators/gamemode_assault.qc b/qcsrc/server/mutators/gamemode_assault.qc new file mode 100644 index 0000000000..94e104728f --- /dev/null +++ b/qcsrc/server/mutators/gamemode_assault.qc @@ -0,0 +1,614 @@ +// 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("", 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 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; +} diff --git a/qcsrc/server/mutators/gamemode_assault.qh b/qcsrc/server/mutators/gamemode_assault.qh new file mode 100644 index 0000000000..9aecf87f29 --- /dev/null +++ b/qcsrc/server/mutators/gamemode_assault.qh @@ -0,0 +1,31 @@ +// 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 diff --git a/qcsrc/server/mutators/gamemode_ca.qc b/qcsrc/server/mutators/gamemode_ca.qc new file mode 100644 index 0000000000..22bfc981c3 --- /dev/null +++ b/qcsrc/server/mutators/gamemode_ca.qc @@ -0,0 +1,283 @@ +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; +} + +MUTATOR_HOOKFUNCTION(ca_SetStartItems) +{ + start_health = cvar("g_lms_start_health"); + start_armorvalue = cvar("g_lms_start_armor"); + + 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_items &~= IT_UNLIMITED_AMMO; + + return 0; +} + +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_HOOK(SetStartItems, ca_SetStartItems, 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."); + ca_Initialize(); + } + + MUTATOR_ONREMOVE + { + print("This is a game type and it cannot be removed at runtime."); + return -1; + } + + return 0; +} diff --git a/qcsrc/server/mutators/gamemode_ca.qh b/qcsrc/server/mutators/gamemode_ca.qh new file mode 100644 index 0000000000..ab0a9d1954 --- /dev/null +++ b/qcsrc/server/mutators/gamemode_ca.qh @@ -0,0 +1,3 @@ +// 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 + diff --git a/qcsrc/server/mutators/gamemode_ctf.qc b/qcsrc/server/mutators/gamemode_ctf.qc index 134e979d1c..8f0bc931ef 100644 --- a/qcsrc/server/mutators/gamemode_ctf.qc +++ b/qcsrc/server/mutators/gamemode_ctf.qc @@ -20,36 +20,45 @@ void ctf_EventLog(string mode, float flagteam, entity actor) // use an alias for GameLogEcho(strcat(":ctf:", mode, ":", ftos(flagteam), ((actor != world) ? (strcat(":", ftos(actor.playerid))) : ""))); } -string ctf_CaptureRecord(entity flag, entity player) +void ctf_CaptureRecord(entity flag, entity player) { - float cap_time, cap_record, success; - string cap_message = string_null, refername; + entity tmp_entity; + float cap_record = ctf_captimerecord; + float cap_time = (time - flag.ctf_pickuptime); + string refername = db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname")); - if((autocvar_g_ctf_captimerecord_always) || (player_count - currentbots)) + // notify about shit + FOR_EACH_REALCLIENT(tmp_entity) { - cap_record = ctf_captimerecord; - cap_time = (time - flag.ctf_pickuptime); - - refername = db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname")); - refername = ((refername == player.netname) ? "their" : strcat(refername, "^7's")); - - if(!ctf_captimerecord) - { cap_message = strcat(" in ", ftos_decimals(cap_time, 2), " seconds"); success = TRUE; } - else if(cap_time < cap_record) - { cap_message = strcat(" in ", ftos_decimals(cap_time, 2), " seconds, breaking ", refername, " previous record of ", ftos_decimals(cap_record, 2), " seconds"); success = TRUE; } - else - { cap_message = strcat(" in ", ftos_decimals(cap_time, 2), " seconds, failing to break ", refername, " record of ", ftos_decimals(cap_record, 2), " seconds"); success = FALSE; } + if(tmp_entity.CAPTURE_VERBOSE) + { + if(!ctf_captimerecord) { Send_Notification(NOTIF_ONE_ONLY, tmp_entity, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_TIME_), player.netname, (cap_time * 100)); } + else if(cap_time < cap_record) { Send_Notification(NOTIF_ONE_ONLY, tmp_entity, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_BROKEN_), player.netname, refername, (cap_time * 100), (cap_record * 100)); } + else { Send_Notification(NOTIF_ONE_ONLY, tmp_entity, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_UNBROKEN_), player.netname, refername, (cap_time * 100), (cap_record * 100)); } + } + else { Send_Notification(NOTIF_ONE_ONLY, tmp_entity, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_), player.netname); } + } - if(success) + // the previous notification broadcast is only sent to real clients, this will notify server log too + if(server_is_dedicated) + { + if(autocvar_notification_ctf_capture_verbose) { - ctf_captimerecord = cap_time; - db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time"), ftos(cap_time)); - db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"), player.netname); - write_recordmarker(player, (time - cap_time), cap_time); - } + if(!ctf_captimerecord) { Local_Notification(MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_TIME_), player.netname, (cap_time * 100)); } + else if(cap_time < cap_record) { Local_Notification(MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_BROKEN_), player.netname, refername, (cap_time * 100), (cap_record * 100)); } + else { Local_Notification(MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_UNBROKEN_), player.netname, refername, (cap_time * 100), (cap_record * 100)); } + } + else { Local_Notification(MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_), player.netname); } } - return cap_message; + // write that shit in the database + if((!ctf_captimerecord) || (cap_time < cap_record)) + { + ctf_captimerecord = cap_time; + db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time"), ftos(cap_time)); + db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"), player.netname); + write_recordmarker(player, (time - cap_time), cap_time); + } } void ctf_FlagcarrierWaypoints(entity player) @@ -165,11 +174,7 @@ void ctf_CaptureShield_Update(entity player, float wanted_status) float updated_status = ctf_CaptureShield_CheckStatus(player); if((wanted_status == player.ctf_captureshielded) && (updated_status != wanted_status)) // 0: shield only, 1: unshield only { - if(updated_status) // TODO csqc notifier for this // Samual: How? - Send_CSQC_Centerprint_Generic(player, CPID_CTF_CAPTURESHIELD, "^3You are now ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Make some defensive scores before trying again.", 5, 0); - else - Send_CSQC_Centerprint_Generic(player, CPID_CTF_CAPTURESHIELD, "^3You are now free.\n\n^3Feel free to ^1try to capture^3 the flag again\n^3if you think you will succeed.", 5, 0); - + Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((updated_status) ? CENTER_CTF_CAPTURESHIELD_SHIELDED : CENTER_CTF_CAPTURESHIELD_FREE)); player.ctf_captureshielded = updated_status; } } @@ -191,7 +196,7 @@ void ctf_CaptureShield_Touch() vector othermid = (other.absmin + other.absmax) * 0.5; Damage(other, self, self, 0, DEATH_HURTTRIGGER, mymid, normalize(othermid - mymid) * ctf_captureshield_force); - Send_CSQC_Centerprint_Generic(other, CPID_CTF_CAPTURESHIELD, "^3You are ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Get some defensive scores before trying again.", 5, 0); + Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_SHIELDED); } void ctf_CaptureShield_Spawn(entity flag) @@ -234,7 +239,7 @@ void ctf_Handle_Drop(entity flag, entity player, float droptype) flag.ctf_status = FLAG_DROPPED; // messages and sounds - Send_KillNotification(player.netname, flag.netname, "", INFO_LOSTFLAG, MSG_INFO); + Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_LOST_), player.netname); sound(flag, CH_TRIGGER, flag.snd_flag_dropped, VOL_BASE, ATTN_NONE); ctf_EventLog("dropped", player.team, player); @@ -287,11 +292,11 @@ void ctf_Handle_Retrieve(entity flag, entity player) FOR_EACH_REALPLAYER(tmp_player) { if(tmp_player == sender) - centerprint(tmp_player, strcat("You passed the ", flag.netname, " to ", player.netname)); + Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_PASS_SENT_), player.netname); else if(tmp_player == player) - centerprint(tmp_player, strcat("You received the ", flag.netname, " from ", sender.netname)); + Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_PASS_RECEIVED_), sender.netname); else if(!IsDifferentTeam(tmp_player, sender)) - centerprint(tmp_player, strcat(sender.netname, " passed the ", flag.netname, " to ", player.netname)); + Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_PASS_OTHER_), sender.netname, player.netname); } // create new waypoint @@ -404,7 +409,8 @@ void ctf_Handle_Capture(entity flag, entity toucher, float capturetype) if not(player) { return; } // without someone to give the reward to, we can't possibly cap // messages and sounds - Send_KillNotification(player.netname, enemy_flag.netname, ctf_CaptureRecord(enemy_flag, player), INFO_CAPTUREFLAG, MSG_INFO); + Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_2(enemy_flag, CENTER_CTF_CAPTURE_)); + ctf_CaptureRecord(enemy_flag, player); sound(player, CH_TRIGGER, flag.snd_flag_capture, VOL_BASE, ATTN_NONE); switch(capturetype) @@ -445,8 +451,8 @@ void ctf_Handle_Capture(entity flag, entity toucher, float capturetype) void ctf_Handle_Return(entity flag, entity player) { // messages and sounds - //centerprint(player, strcat("You returned the ", flag.netname)); - Send_KillNotification(player.netname, flag.netname, "", INFO_RETURNFLAG, MSG_INFO); + Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_RETURN_)); + Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_RETURN_), player.netname); sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTN_NONE); ctf_EventLog("return", flag.team, player); @@ -471,7 +477,6 @@ void ctf_Handle_Pickup(entity flag, entity player, float pickuptype) { // declarations entity tmp_player; // temporary entity which the FOR_EACH_PLAYER loop uses to scan players - string verbosename; // holds the name of the player OR no name at all for printing in the centerprints float pickup_dropped_score; // used to calculate dropped pickup score // attach the flag to the player @@ -495,21 +500,30 @@ void ctf_Handle_Pickup(entity flag, entity player, float pickuptype) } // messages and sounds - Send_KillNotification (player.netname, flag.netname, "", INFO_GOTFLAG, MSG_INFO); + Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_PICKUP_), player.netname); sound(player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTN_NONE); - verbosename = ((autocvar_g_ctf_flag_pickup_verbosename) ? strcat(Team_ColorCode(player.team), "(^7", player.netname, Team_ColorCode(player.team), ") ") : ""); - + FOR_EACH_REALPLAYER(tmp_player) { if(tmp_player == player) { - centerprint(tmp_player, strcat("You got the ", flag.netname, "!")); - //if(ctf_stalemate) { centerprint(tmp_player, "Stalemate! Enemies can see you on radar!"); } + Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_PICKUP_)); + if(ctf_stalemate) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_STALEMATE_CARRIER); } + } + else if(!IsDifferentTeam(tmp_player, player) && tmp_player != player) + { + if(tmp_player.PICKUP_TEAM_VERBOSE) + Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, CENTER_CTF_PICKUP_TEAM_VERBOSE, Team_ColorCode(player.team), player.netname); + else + Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, CENTER_CTF_PICKUP_TEAM, Team_ColorCode(player.team)); + } + else if(IsDifferentTeam(tmp_player, player)) + { + if(tmp_player.PICKUP_ENEMY_VERBOSE) + Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, CENTER_CTF_PICKUP_ENEMY_VERBOSE, Team_ColorCode(player.team), player.netname); + else + Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, CENTER_CTF_PICKUP_ENEMY, Team_ColorCode(player.team)); } - //else if(!IsDifferentTeam(tmp_player, player)) - // centerprint(tmp_player, strcat("Your ", Team_ColorCode(player.team), "team mate ", verbosename, "^7got the flag! Protect them!")); - else if(!IsDifferentTeam(tmp_player, flag)) - centerprint(tmp_player, strcat("The ", Team_ColorCode(player.team), "enemy ", verbosename, "^7got your flag! Retrieve it!")); } // scoring @@ -568,14 +582,14 @@ void ctf_CheckFlagReturn(entity flag, float returntype) { switch(returntype) { - case RETURN_DROPPED: bprint("The ", flag.netname, " was dropped in the base and returned itself\n"); break; - case RETURN_DAMAGE: bprint("The ", flag.netname, " was destroyed and returned to base\n"); break; - case RETURN_SPEEDRUN: bprint("The ", flag.netname, " became impatient after ", ftos_decimals(ctf_captimerecord, 2), " seconds and returned itself\n"); break; - case RETURN_NEEDKILL: bprint("The ", flag.netname, " fell somewhere it couldn't be reached and returned to base\n"); break; + case RETURN_DROPPED: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_DROPPED_)); break; + case RETURN_DAMAGE: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_DAMAGED_)); break; + case RETURN_SPEEDRUN: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_SPEEDRUN_), ctf_captimerecord); break; + case RETURN_NEEDKILL: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_NEEDKILL_)); break; default: case RETURN_TIMEOUT: - { bprint("The ", flag.netname, " has returned to base\n"); break; } + { Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_TIMEOUT_)); break; } } sound(flag, CH_TRIGGER, flag.snd_flag_respawn, VOL_BASE, ATTN_NONE); ctf_EventLog("returned", flag.team, world); @@ -604,8 +618,8 @@ void ctf_CheckStalemate(void) switch(tmp_entity.team) { - case COLOR_TEAM1: ++stale_red_flags; break; - case COLOR_TEAM2: ++stale_blue_flags; break; + case NUM_TEAM_1: ++stale_red_flags; break; + case NUM_TEAM_2: ++stale_blue_flags; break; } } } @@ -629,10 +643,7 @@ void ctf_CheckStalemate(void) if not(wpforenemy_announced) { FOR_EACH_REALPLAYER(tmp_entity) - if(tmp_entity.flagcarried) - centerprint(tmp_entity, "Stalemate! Enemies can now see you on radar!"); - else - centerprint(tmp_entity, "Stalemate! Flag carriers can now be seen by enemies on radar!"); + Send_Notification(NOTIF_ONE, tmp_entity, MSG_CENTER, ((tmp_entity.flagcarried) ? CENTER_CTF_STALEMATE_CARRIER : CENTER_CTF_STALEMATE_OTHER)); wpforenemy_announced = TRUE; } @@ -931,7 +942,7 @@ void ctf_DelayedFlagSetup(void) // called after a flag is placed on a map by ctf self.bot_basewaypoint = self.nearestwaypoint; // waypointsprites - WaypointSprite_SpawnFixed(((self.team == COLOR_TEAM1) ? "redbase" : "bluebase"), self.origin + FLAG_WAYPOINT_OFFSET, self, wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, FALSE)); + WaypointSprite_SpawnFixed(((self.team == NUM_TEAM_1) ? "redbase" : "bluebase"), self.origin + FLAG_WAYPOINT_OFFSET, self, wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, FALSE)); WaypointSprite_UpdateTeamRadar(self.wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, FALSE)); // captureshield setup @@ -948,10 +959,10 @@ void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag flag.ctf_worldflagnext = ctf_worldflaglist; // link flag into ctf_worldflaglist ctf_worldflaglist = flag; - setattachment(flag, world, ""); + setattachment(flag, world, ""); - flag.netname = ((teamnumber) ? "^1RED^7 flag" : "^4BLUE^7 flag"); - flag.team = ((teamnumber) ? COLOR_TEAM1 : COLOR_TEAM2); // COLOR_TEAM1: color 4 team (red) - COLOR_TEAM2: color 13 team (blue) + flag.netname = ((teamnumber) ? "^1REPLACETHIS^7" : "^4REPLACETHIS^7"); // ((teamnumber) ? "^1RED^7 flag" : "^4BLUE^7 flag"); + flag.team = ((teamnumber) ? NUM_TEAM_1 : NUM_TEAM_2); // NUM_TEAM_1: color 4 team (red) - NUM_TEAM_2: color 13 team (blue) flag.items = ((teamnumber) ? IT_KEY2 : IT_KEY1); // IT_KEY2: gold key (redish enough) - IT_KEY1: silver key (bluish enough) flag.classname = "item_flag_team"; flag.target = "###item###"; // wut? @@ -1762,6 +1773,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerDamage) // for changing damage and force values t frag_target.wps_helpme_time = time; WaypointSprite_HelpMePing(frag_target.wps_flagcarrier); } + // todo: add notification for when flag carrier needs help? } return FALSE; } @@ -1842,13 +1854,13 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey) { if(clienttype(head) == CLIENTTYPE_BOT) { - centerprint(player, strcat("Requesting ", head.netname, " to pass you the ", head.flagcarried.netname)); + Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname); ctf_Handle_Throw(head, player, DROP_PASS); } else { - centerprint(head, strcat(player.netname, " requests you to pass the ", head.flagcarried.netname)); - centerprint(player, strcat("Requesting ", head.netname, " to pass you the ", head.flagcarried.netname)); + Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_CTF_PASS_REQUESTED, player.netname); + Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname); } player.throw_antispam = time + autocvar_g_ctf_pass_wait; return TRUE; @@ -1885,7 +1897,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey) } else { - centerprint(player, strcat("Too many flag throws, throwing disabled for ", ftos(rint((player.throw_prevtime + autocvar_g_ctf_throw_punish_delay) - time)), " seconds.")); + Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_FLAG_THROW_PUNISH, rint((player.throw_prevtime + autocvar_g_ctf_throw_punish_delay) - time)); return FALSE; } } @@ -1960,8 +1972,8 @@ MUTATOR_HOOKFUNCTION(ctf_AbortSpeedrun) { if(self.flagcarried) { - bprint("The ", self.flagcarried.netname, " was returned to base by its carrier\n"); - ctf_RespawnFlag(self); + Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(self.flagcarried, INFO_CTF_FLAGRETURN_ABORTRUN_)); + ctf_RespawnFlag(self.flagcarried); return TRUE; } @@ -2008,6 +2020,14 @@ MUTATOR_HOOKFUNCTION(ctf_BotRoles) return TRUE; } +MUTATOR_HOOKFUNCTION(ctf_GetCvars) +{ + GetCvars_handleFloat(get_cvars_s, get_cvars_f, CAPTURE_VERBOSE, "notification_ctf_capture_verbose"); + GetCvars_handleFloat(get_cvars_s, get_cvars_f, PICKUP_TEAM_VERBOSE, "notification_ctf_pickup_team_verbose"); + GetCvars_handleFloat(get_cvars_s, get_cvars_f, PICKUP_ENEMY_VERBOSE, "notification_ctf_pickup_enemy_verbose"); + return TRUE; +} + // ========== // Spawnfuncs @@ -2020,7 +2040,7 @@ void spawnfunc_info_player_team1() { if(g_assault) { remove(self); return; } - self.team = COLOR_TEAM1; // red + self.team = NUM_TEAM_1; // red spawnfunc_info_player_deathmatch(); } @@ -2032,7 +2052,7 @@ void spawnfunc_info_player_team2() { if(g_assault) { remove(self); return; } - self.team = COLOR_TEAM2; // blue + self.team = NUM_TEAM_2; // blue spawnfunc_info_player_deathmatch(); } @@ -2043,7 +2063,7 @@ void spawnfunc_info_player_team3() { if(g_assault) { remove(self); return; } - self.team = COLOR_TEAM3; // yellow + self.team = NUM_TEAM_3; // yellow spawnfunc_info_player_deathmatch(); } @@ -2055,7 +2075,7 @@ void spawnfunc_info_player_team4() { if(g_assault) { remove(self); return; } - self.team = COLOR_TEAM4; // purple + self.team = NUM_TEAM_4; // purple spawnfunc_info_player_deathmatch(); } @@ -2157,8 +2177,8 @@ void ctf_DelayedInit() // Do this check with a delay so we can wait for teams to if(find(world, classname, "ctf_team") == world) { print("No ""ctf_team"" entities found on this map, creating them anyway.\n"); - ctf_SpawnTeam("Red", COLOR_TEAM1 - 1); - ctf_SpawnTeam("Blue", COLOR_TEAM2 - 1); + ctf_SpawnTeam("Red", NUM_TEAM_1 - 1); + ctf_SpawnTeam("Blue", NUM_TEAM_2 - 1); } ctf_ScoreRules(); @@ -2192,6 +2212,7 @@ MUTATOR_DEFINITION(gamemode_ctf) MUTATOR_HOOK(VehicleExit, ctf_VehicleExit, CBC_ORDER_ANY); MUTATOR_HOOK(AbortSpeedrun, ctf_AbortSpeedrun, CBC_ORDER_ANY); MUTATOR_HOOK(HavocBot_ChooseRule, ctf_BotRoles, CBC_ORDER_ANY); + MUTATOR_HOOK(GetCvars, ctf_GetCvars, CBC_ORDER_ANY); MUTATOR_ONADD { diff --git a/qcsrc/server/mutators/gamemode_ctf.qh b/qcsrc/server/mutators/gamemode_ctf.qh index 1c5898bd1a..882b1064b4 100644 --- a/qcsrc/server/mutators/gamemode_ctf.qh +++ b/qcsrc/server/mutators/gamemode_ctf.qh @@ -1,5 +1,6 @@ // these are needed since mutators are compiled last +#ifdef SVQC // used in cheats.qc void ctf_RespawnFlag(entity flag); @@ -130,3 +131,13 @@ vector havocbot_ctf_middlepoint; float havocbot_ctf_middlepoint_radius; void havocbot_role_ctf_setrole(entity bot, float role); + +// client notification stuff +.float CAPTURE_VERBOSE; +.float PICKUP_TEAM_VERBOSE; +.float PICKUP_ENEMY_VERBOSE; +#else +var float autocvar_notification_ctf_pickup_team_verbose = FALSE; +var float autocvar_notification_ctf_pickup_enemy_verbose = FALSE; +#endif +var float autocvar_notification_ctf_capture_verbose = FALSE; diff --git a/qcsrc/server/mutators/gamemode_domination.qc b/qcsrc/server/mutators/gamemode_domination.qc index 852fb90c05..98b9b40dd8 100644 --- a/qcsrc/server/mutators/gamemode_domination.qc +++ b/qcsrc/server/mutators/gamemode_domination.qc @@ -19,6 +19,7 @@ void dompoint_captured () { 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; @@ -74,22 +75,17 @@ void dompoint_captured () SUB_UseTargets (); self.delay = old_delay; self.team = old_team; - - switch(self.goalentity.team) + + switch(self.team) { - case COLOR_TEAM1: - WaypointSprite_UpdateSprites(self.sprite, "dom-red", "", ""); - break; - case COLOR_TEAM2: - WaypointSprite_UpdateSprites(self.sprite, "dom-blue", "", ""); - break; - case COLOR_TEAM3: - WaypointSprite_UpdateSprites(self.sprite, "dom-yellow", "", ""); - break; - case COLOR_TEAM4: - WaypointSprite_UpdateSprites(self.sprite, "dom-pink", "", ""); + 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, 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; ) { @@ -103,16 +99,16 @@ void dompoint_captured () wait_time = head.wait; switch(head.goalentity.team) { - case COLOR_TEAM1: + case NUM_TEAM_1: pps_red += points/wait_time; break; - case COLOR_TEAM2: + case NUM_TEAM_2: pps_blue += points/wait_time; break; - case COLOR_TEAM3: + case NUM_TEAM_3: pps_yellow += points/wait_time; break; - case COLOR_TEAM4: + case NUM_TEAM_4: pps_pink += points/wait_time; } total_pps += points/wait_time; @@ -454,12 +450,12 @@ void dom_spawnteams() { float numteams = ((autocvar_g_domination_teams_override < 2) ? autocvar_g_domination_default_teams : autocvar_g_domination_teams_override); - dom_spawnteam("Red", COLOR_TEAM1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point"); - dom_spawnteam("Blue", COLOR_TEAM2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point"); + dom_spawnteam("Red", NUM_TEAM_1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point"); + dom_spawnteam("Blue", NUM_TEAM_2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point"); if(numteams > 2) - dom_spawnteam("Yellow", COLOR_TEAM3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point"); + dom_spawnteam("Yellow", NUM_TEAM_3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point"); if(numteams > 3) - dom_spawnteam("Pink", COLOR_TEAM4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point"); + dom_spawnteam("Pink", NUM_TEAM_4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point"); dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, "", "", ""); } diff --git a/qcsrc/server/mutators/gamemode_freezetag.qc b/qcsrc/server/mutators/gamemode_freezetag.qc index 116eecbbf6..980a9b20d9 100644 --- a/qcsrc/server/mutators/gamemode_freezetag.qc +++ b/qcsrc/server/mutators/gamemode_freezetag.qc @@ -1,57 +1,131 @@ -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; - string teamname; - 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) { - if(winner.team == COLOR_TEAM1) - teamname = "^1Red Team"; - else if(winner.team == COLOR_TEAM2) - teamname = "^4Blue Team"; - else if(winner.team == COLOR_TEAM3) - teamname = "^3Yellow Team"; - else - teamname = "^6Pink Team"; - FOR_EACH_PLAYER(e) { - centerprint(e, strcat(teamname, "^5 wins the round, all other teams were frozen.\n")); - } - bprint(teamname, "^5 wins the round since all the other teams were frozen.\n"); - 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 @@ -63,13 +137,36 @@ void freezetag_Ice_Think() 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(); @@ -78,53 +175,31 @@ void freezetag_Freeze(entity attacker) 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); } @@ -240,112 +315,151 @@ void havocbot_role_ft_freeing() MUTATOR_HOOKFUNCTION(freezetag_RemovePlayer) { - if(self.freezetag_frozen == 0 && self.health >= 1) - { - if(self.team == COLOR_TEAM1) - --redalive; - else if(self.team == COLOR_TEAM2) - --bluealive; - else if(self.team == COLOR_TEAM3) - --yellowalive; - else if(self.team == COLOR_TEAM4) - --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 == COLOR_TEAM1) - --redalive; - else if(self.team == COLOR_TEAM2) - --bluealive; - else if(self.team == COLOR_TEAM3) - --yellowalive; - else if(self.team == COLOR_TEAM4) - --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) - centerprint(frag_target, "^1You froze yourself.\n"); - bprint("^7", frag_target.netname, "^1 froze himself.\n"); + Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_SELF); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_SELF, frag_target.netname); } else { if(frag_target.classname == STR_PLAYER) - centerprint(frag_target, strcat("^1You were frozen by ^7", frag_attacker.netname, ".\n")); + Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_FROZEN, frag_attacker.netname); if(frag_attacker.classname == STR_PLAYER) - centerprint(frag_attacker, strcat("^2You froze ^7", frag_target.netname, ".\n")); - bprint("^7", frag_target.netname, "^1 was frozen by ^7", frag_attacker.netname, ".\n"); + Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_FREEZETAG_FREEZE, frag_target.netname); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_FREEZE, frag_target.netname, frag_attacker.netname); } 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()) { - centerprint(self, "^1You spawned after the round started, you'll spawn as frozen.\n"); + 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; + } } } } @@ -353,50 +467,42 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink) 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); } } - if(n > 1) - centerprint(self, strcat("^5You were revived by ^7", o.netname, "^5 et al.\n")); - else - centerprint(self, strcat("^5You were revived by ^7", o.netname, "^5.\n")); - centerprint(o, strcat("^5You revived ^7", self.netname, "^5.\n")); - if(n > 1) - bprint("^7", o.netname, "^5 et al revived ^7", self.netname, "^5.\n"); - else - bprint("^7", o.netname, "^5 revived ^7", self.netname, "^5.\n"); + 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_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; } } } @@ -425,15 +531,12 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPhysics) 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) @@ -443,6 +546,13 @@ 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) @@ -452,22 +562,60 @@ MUTATOR_HOOKFUNCTION(freezetag_BotRoles) 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 { diff --git a/qcsrc/server/mutators/gamemode_keepaway.qc b/qcsrc/server/mutators/gamemode_keepaway.qc index 3be0b03527..7a16cd62b2 100644 --- a/qcsrc/server/mutators/gamemode_keepaway.qc +++ b/qcsrc/server/mutators/gamemode_keepaway.qc @@ -101,9 +101,8 @@ void ka_TouchEvent() // runs any time that the ball comes in contact with someth // messages and sounds ka_EventLog("pickup", other); - Send_KillNotification(other.netname, "", "", KA_PICKUPBALL, MSG_KA); - WriteByte(MSG_BROADCAST, SVC_CENTERPRINT); - WriteString(MSG_BROADCAST, strcat(other.netname, "^7 has picked up the ball!")); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_KEEPAWAY_PICKUP, other.netname); + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_KEEPAWAY_PICKUP, other.netname); sound(self.owner, CH_TRIGGER, "keepaway/pickedup.wav", VOL_BASE, ATTN_NONE); // ATTN_NONE (it's a sound intended to be heard anywhere) // scoring @@ -144,9 +143,8 @@ void ka_DropEvent(entity plyr) // runs any time that a player is supposed to los // messages and sounds ka_EventLog("dropped", plyr); - Send_KillNotification(plyr.netname, "", "", KA_DROPBALL, MSG_KA); - WriteByte(MSG_BROADCAST, SVC_CENTERPRINT); - WriteString(MSG_BROADCAST, strcat(plyr.netname, "^7 has dropped the ball!")); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_KEEPAWAY_DROPPED, plyr.netname); + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_KEEPAWAY_DROPPED, plyr.netname); sound(other, CH_TRIGGER, "keepaway/dropped.wav", VOL_BASE, ATTN_NONE); // ATTN_NONE (it's a sound intended to be heard anywhere) // scoring @@ -254,7 +252,7 @@ MUTATOR_HOOKFUNCTION(ka_Scoring) } else if(!frag_attacker.ballcarried) if(autocvar_g_keepaway_noncarrier_warn) - centerprint(frag_attacker, "Killing people while you don't have the ball gives no points!"); + Send_Notification(NOTIF_ONE_ONLY, frag_attacker, MSG_CENTER, CENTER_KEEPAWAY_WARN); if(frag_attacker.ballcarried) // add to amount of kills while ballcarrier PlayerScore_Add(frag_attacker, SP_SCORE, autocvar_g_keepaway_score_killac); diff --git a/qcsrc/server/mutators/gamemode_keyhunt.qc b/qcsrc/server/mutators/gamemode_keyhunt.qc index 592fa327cf..13a06c367c 100644 --- a/qcsrc/server/mutators/gamemode_keyhunt.qc +++ b/qcsrc/server/mutators/gamemode_keyhunt.qc @@ -20,7 +20,6 @@ vector KH_KEY_MIN = '-10 -10 -46'; vector KH_KEY_MAX = '10 10 3'; float KH_KEY_BRIGHTNESS = 2; -string kh_Controller_Waitmsg; float kh_no_radar_circles; // kh_state @@ -40,10 +39,10 @@ float kh_keystatus[17]; float kh_Team_ByID(float t) { - if(t == 0) return COLOR_TEAM1; - if(t == 1) return COLOR_TEAM2; - if(t == 2) return COLOR_TEAM3; - if(t == 3) return COLOR_TEAM4; + if(t == 0) return NUM_TEAM_1; + if(t == 1) return NUM_TEAM_2; + if(t == 2) return NUM_TEAM_3; + if(t == 3) return NUM_TEAM_4; return 0; } @@ -122,50 +121,20 @@ void kh_update_state() var kh_Think_t kh_Controller_Thinkfunc; -void kh_Controller_SetThink(float t, string msg, float centerprint_duration, kh_Think_t func) // runs occasionaly +void kh_Controller_SetThink(float t, kh_Think_t func) // runs occasionaly { kh_Controller_Thinkfunc = func; kh_controller.cnt = ceil(t); - if(kh_Controller_Waitmsg != "") - strunzone(kh_Controller_Waitmsg); - if(msg == "") - kh_Controller_Waitmsg = ""; - else - { - kh_controller.kh_cp_duration = centerprint_duration; - kh_Controller_Waitmsg = strzone(msg); - } if(t == 0) kh_controller.nextthink = time; // force } -void kh_Controller_SetThink_NoMsg(float t, kh_Think_t func) // runs occasionaly -{ - kh_Controller_SetThink(t, "", 0, func); -} - +void kh_WaitForPlayers(); void kh_Controller_Think() // called a lot { - entity e; if(intermission_running) return; if(self.cnt > 0) - { - if(kh_Controller_Waitmsg != "") - { - string s; - if(substring(kh_Controller_Waitmsg, strlen(kh_Controller_Waitmsg)-1, 1) == " ") - s = strcat(kh_Controller_Waitmsg, ftos(self.cnt)); - else - s = kh_Controller_Waitmsg; - - //dprint(s, "\n"); - - FOR_EACH_PLAYER(e) - if(clienttype(e) == CLIENTTYPE_REAL) - Send_CSQC_Centerprint_Generic(e, CPID_KH_MSG, s, self.kh_cp_duration, 0); - } - self.cnt -= 1; - } + { if(self.think != kh_WaitForPlayers) { self.cnt -= 1; } } else if(self.cnt == 0) { self.cnt -= 1; @@ -361,13 +330,13 @@ void kh_Key_AssignTo(entity key, entity player) // runs every time a key is pic WaypointSprite_AttachCarrier("", player, RADARICON_FLAGCARRIER, colormapPaletteColor(player.team - 1, 0)); player.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = kh_KeyCarrier_waypointsprite_visible_for_player; WaypointSprite_UpdateRule(player.waypointsprite_attachedforcarrier, player.team, SPRITERULE_TEAMPLAY); - if(player.team == COLOR_TEAM1) + if(player.team == NUM_TEAM_1) WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, "keycarrier-red", "keycarrier-friend", "keycarrier-red"); - else if(player.team == COLOR_TEAM2) + else if(player.team == NUM_TEAM_2) WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, "keycarrier-blue", "keycarrier-friend", "keycarrier-blue"); - else if(player.team == COLOR_TEAM3) + else if(player.team == NUM_TEAM_3) WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, "keycarrier-yellow", "keycarrier-friend", "keycarrier-yellow"); - else if(player.team == COLOR_TEAM4) + else if(player.team == NUM_TEAM_4) WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, "keycarrier-pink", "keycarrier-friend", "keycarrier-pink"); if(!kh_no_radar_circles) WaypointSprite_Ping(player.waypointsprite_attachedforcarrier); @@ -436,7 +405,7 @@ void kh_Key_Collect(entity key, entity player) //a player picks up a dropped ke PlayerScore_Add(player, SP_KH_PICKUPS, 1); } key.kh_dropperteam = 0; - bprint(player.netname, "^7 picked up the ", key.netname, "\n"); + Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(key, INFO_KEYHUNT_PICKUP_), player.netname); kh_Key_AssignTo(key, player); // this also updates .kh_state } @@ -510,10 +479,11 @@ void kh_FinishRound() // runs when a team captures the keys kh_Key_Remove(key); kh_no_radar_circles = FALSE; - kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round, "Round starts in ", 1, kh_StartRound); + 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); } -void kh_WinnerTeam(float teem) // runs when a team wins +void kh_WinnerTeam(float teem) // runs when a team wins // Samual: Teem?.... TEEM?!?! what the fuck is wrong with you people { // all key carriers get some points vector firstorigin, lastorigin, midpoint; @@ -533,15 +503,17 @@ void kh_WinnerTeam(float teem) // runs when a team wins } first = TRUE; + string keyowner = ""; FOR_EACH_KH_KEY(key) if(key.owner.kh_next == key) { if(!first) - bprint("^7, "); - bprint(key.owner.netname); + keyowner = strcat(keyowner, ", "); + keyowner = key.owner.netname; first = FALSE; } - bprint("^7 captured the keys for the ", ColoredTeamName(teem), "\n"); + + Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(teem, INFO_KEYHUNT_CAPTURE_), keyowner); first = TRUE; midpoint = '0 0 0'; @@ -567,7 +539,7 @@ void kh_WinnerTeam(float teem) // runs when a team wins te_lightning2(world, lastorigin, firstorigin); } midpoint = midpoint * (1 / kh_teams); - te_customflash(midpoint, 1000, 1, TeamColor(teem) * 0.5 + '0.5 0.5 0.5'); // make the color >=0.5 in each component + te_customflash(midpoint, 1000, 1, Team_ColorRGB(teem) * 0.5 + '0.5 0.5 0.5'); // make the color >=0.5 in each component play2all(kh_sound_capture); kh_FinishRound(); @@ -595,8 +567,7 @@ void kh_LoserTeam(float teem, entity lostkey) // runs when a player pushes a fl // don't actually GIVE him the -nn points, just log kh_Scores_Event(attacker, world, "push", autocvar_g_balance_keyhunt_score_push, 0); PlayerScore_Add(attacker, SP_KH_PUSHES, 1); - centerprint(attacker, "Your push is the best!"); - bprint("The ", ColoredTeamName(teem), "^7 could not take care of the ", lostkey.netname, "^7 when ", attacker.netname, "^7 came\n"); + //centerprint(attacker, "Your push is the best!"); // does this really need to exist? } else { @@ -655,9 +626,10 @@ void kh_LoserTeam(float teem, entity lostkey) // runs when a player pushes a fl --j; } - - bprint("The ", ColoredTeamName(teem), "^7 could not take care of the ", lostkey.netname, "\n"); } + + Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(lostkey, INFO_KEYHUNT_LOST_), lostkey.kh_previous_owner.netname); + play2all(kh_sound_destroy); te_tarexplosion(lostkey.origin); @@ -711,11 +683,11 @@ void kh_Key_Think() // runs all the time { if(head.team == kh_interferemsg_team) if(head.kh_next) - Send_CSQC_Centerprint_Generic(head, CPID_KH_MSG, "All keys are in your team's hands!\n\nMeet the other key carriers ^1NOW^7!", 0, 0); + Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_KEYHUNT_MEET); else - Send_CSQC_Centerprint_Generic(head, CPID_KH_MSG, "All keys are in your team's hands!\n\nHelp the key carriers to meet!", 0, 0); + Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_KEYHUNT_HELP); else - Send_CSQC_Centerprint_Generic(head, CPID_KH_MSG, strcat("All keys are in the ", ColoredTeamName(kh_interferemsg_team), "^7's hands!\n\nInterfere ^1NOW^7!"), 0, 0); + Send_Notification(NOTIF_ONE, head, MSG_CENTER, APP_TEAM_NUM_4(kh_interferemsg_team, CENTER_KEYHUNT_INTERFERE_)); } } @@ -748,21 +720,21 @@ void kh_Key_Spawn(entity initial_owner, float angle, float i) // runs every tim key.kh_dropperteam = 0; key.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP; setsize(key, KH_KEY_MIN, KH_KEY_MAX); - key.colormod = TeamColor(initial_owner.team) * KH_KEY_BRIGHTNESS; + key.colormod = Team_ColorRGB(initial_owner.team) * KH_KEY_BRIGHTNESS; key.reset = key_reset; switch(initial_owner.team) { - case COLOR_TEAM1: + case NUM_TEAM_1: key.netname = "^1red key"; break; - case COLOR_TEAM2: + case NUM_TEAM_2: key.netname = "^4blue key"; break; - case COLOR_TEAM3: + case NUM_TEAM_3: key.netname = "^3yellow key"; break; - case COLOR_TEAM4: + case NUM_TEAM_4: key.netname = "^6pink key"; break; default: @@ -774,7 +746,7 @@ void kh_Key_Spawn(entity initial_owner, float angle, float i) // runs every tim key.kh_worldkeynext = kh_worldkeylist; kh_worldkeylist = key; - centerprint(initial_owner, strcat("You are starting with the ", key.netname, "\n")); // message to player at start of round + Send_Notification(NOTIF_ONE, initial_owner, MSG_CENTER, APP_TEAM_NUM_4(initial_owner.team, CENTER_KEYHUNT_START_)); WaypointSprite_Spawn("key-dropped", 0, 0, key, '0 0 1' * KH_KEY_WP_ZSHIFT, world, key.team, key, waypointsprite_attachedforcarrier, FALSE, RADARICON_FLAG, '0 1 1'); key.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = kh_Key_waypointsprite_visible_for_player; @@ -817,7 +789,8 @@ void kh_Key_DropOne(entity key) kh_Scores_Event(player, key, "dropkey", 0, 0); PlayerScore_Add(player, SP_KH_LOSSES, 1); - bprint(player.netname, "^7 dropped the ", key.netname, "\n"); + Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(key, INFO_KEYHUNT_DROP_), player.netname); + kh_Key_AssignTo(key, world); makevectors(player.v_angle); key.velocity = W_CalculateProjectileVelocity(player.velocity, autocvar_g_balance_keyhunt_throwvelocity * v_forward, FALSE); @@ -842,7 +815,7 @@ void kh_Key_DropAll(entity player, float suicide) // runs whenever a player dies { kh_Scores_Event(player, key, "losekey", 0, 0); PlayerScore_Add(player, SP_KH_LOSSES, 1); - bprint(player.netname, "^7 died and lost the ", key.netname, "\n"); + Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(key, INFO_KEYHUNT_LOST_), player.netname); kh_Key_AssignTo(key, world); makevectors('-1 0 0' * (45 + 45 * random()) + '0 360 0' * random()); key.velocity = W_CalculateProjectileVelocity(player.velocity, autocvar_g_balance_keyhunt_dropvelocity * v_forward, FALSE); @@ -855,83 +828,74 @@ void kh_Key_DropAll(entity player, float suicide) // runs whenever a player dies } } -string kh_CheckEnoughPlayers() // checks enough player are present, runs after every completed round +float kh_CheckPlayers(float num) { - float i, players, teem; - entity player; - string result; - result = ""; - - // find a random player per team - for(i = 0; i < kh_teams; ++i) + if(num < kh_teams) { - teem = kh_Team_ByID(i); - players = 0; - FOR_EACH_PLAYER(player) - if(player.deadflag == DEAD_NO) - if(!player.BUTTON_CHAT) - if(player.team == teem) + float t_team = kh_Team_ByID(num); + float players = 0; + entity tmp_player; + FOR_EACH_PLAYER(tmp_player) + if(tmp_player.deadflag == DEAD_NO) + if(!tmp_player.BUTTON_CHAT) + if(tmp_player.team == t_team) ++players; - if(players == 0) - { - if(result != "") - result = strcat(result, ", "); - result = strcat(result, ColoredTeamName(teem)); - } + + if not(players) { return t_team; } } - return result; + return 0; } void kh_WaitForPlayers() // delay start of the round until enough players are present { - string teams_missing; - if(time < game_starttime) { - kh_Controller_SetThink_NoMsg(game_starttime - time + 0.1, kh_WaitForPlayers); + kh_Controller_SetThink(game_starttime - time + 0.1, kh_WaitForPlayers); return; } - teams_missing = kh_CheckEnoughPlayers(); - if(teams_missing == "") - kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round, "Round starts in ", 1, 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_KEYHUNT_ROUNDSTART, autocvar_g_balance_keyhunt_delay_round); + kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round, kh_StartRound); + } else - kh_Controller_SetThink(1, strcat("Waiting for players to join...\n\nNeed active players for: ", teams_missing), -1, kh_WaitForPlayers); + { + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_KEYHUNT_WAIT, p1, p2, p3, p4); + kh_Controller_SetThink(1, kh_WaitForPlayers); + } } void kh_EnableTrackingDevice() // runs after each round { - entity player; - - FOR_EACH_PLAYER(player) - if(clienttype(player) == CLIENTTYPE_REAL) - Send_CSQC_Centerprint_Generic_Expire(player, CPID_KH_MSG); + Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_KEYHUNT); + Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_KEYHUNT_OTHER); kh_tracking_enabled = TRUE; } void kh_StartRound() // runs at the start of each round { - string teams_missing; float i, players, teem; entity player; if(time < game_starttime) { - kh_Controller_SetThink_NoMsg(game_starttime - time + 0.1, kh_WaitForPlayers); + kh_Controller_SetThink(game_starttime - time + 0.1, kh_WaitForPlayers); return; } - teams_missing = kh_CheckEnoughPlayers(); - if(teams_missing != "") + float p1 = kh_CheckPlayers(0), p2 = kh_CheckPlayers(1), p3 = kh_CheckPlayers(2), p4 = kh_CheckPlayers(3); + if(p1 || p2 || p3 || p4) { - kh_Controller_SetThink(1, strcat("Waiting for players to join...\n\nNeed active players for: ", teams_missing), -1, kh_WaitForPlayers); + kh_Controller_SetThink(1, kh_WaitForPlayers); + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_KEYHUNT_WAIT, p1, p2, p3, p4); return; } - - FOR_EACH_PLAYER(player) - if(clienttype(player) == CLIENTTYPE_REAL) - Send_CSQC_Centerprint_Generic_Expire(player, CPID_KH_MSG); + + Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_KEYHUNT); + Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_KEYHUNT_OTHER); for(i = 0; i < kh_teams; ++i) { @@ -951,7 +915,8 @@ void kh_StartRound() // runs at the start of each round } kh_tracking_enabled = FALSE; - kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_tracking, "Scanning frequency range...", -1, kh_EnableTrackingDevice); + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_KEYHUNT_SCAN, autocvar_g_balance_keyhunt_delay_tracking); + kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_tracking, kh_EnableTrackingDevice); } float kh_HandleFrags(entity attacker, entity targ, float f) // adds to the player score @@ -1003,7 +968,7 @@ void kh_Initialize() // sets up th KH environment // make a KH entity for controlling the game kh_controller = spawn(); kh_controller.think = kh_Controller_Think; - kh_Controller_SetThink_NoMsg(0, kh_WaitForPlayers); + kh_Controller_SetThink(0, kh_WaitForPlayers); setmodel(kh_controller, "models/keyhunt/key.md3"); kh_key_dropped = kh_controller.modelindex; diff --git a/qcsrc/server/mutators/gamemode_keyhunt.qh b/qcsrc/server/mutators/gamemode_keyhunt.qh index 8ee8434293..611f7f065e 100644 --- a/qcsrc/server/mutators/gamemode_keyhunt.qh +++ b/qcsrc/server/mutators/gamemode_keyhunt.qh @@ -6,7 +6,6 @@ float kh_tracking_enabled; .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_NoMsg(float t, kh_Think_t func); +void kh_Controller_SetThink(float t, kh_Think_t func); diff --git a/qcsrc/server/mutators/gamemode_lms.qc b/qcsrc/server/mutators/gamemode_lms.qc new file mode 100644 index 0000000000..82258ac77c --- /dev/null +++ b/qcsrc/server/mutators/gamemode_lms.qc @@ -0,0 +1,274 @@ +// 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_ResetMap) +{ + lms_lowest_lives = 999; + lms_next_place = player_count; + + return FALSE; +} + +MUTATOR_HOOKFUNCTION(lms_ResetPlayers) +{ + if(restart_mapalreadyrestarted || (time < game_starttime)) + FOR_EACH_CLIENT(self) + if(IS_PLAYER(self)) + PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives()); + + return FALSE; +} + +MUTATOR_HOOKFUNCTION(lms_PlayerPreSpawn) +{ + // player is dead and becomes observer + // FIXME fix LMS scoring for new system + if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0) + self.classname = "observer"; + + return FALSE; +} + +MUTATOR_HOOKFUNCTION(lms_PlayerSpawn) +{ + self.lms_nextcheck = time + autocvar_g_lms_campcheck_interval*2; + self.lms_traveled_distance = 0; + + return FALSE; +} + +MUTATOR_HOOKFUNCTION(lms_PlayerDies) +{ + self.respawn_flags |= RESPAWN_FORCE; + + 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; +} + +// 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(reset_map_global, lms_ResetMap, CBC_ORDER_ANY); + MUTATOR_HOOK(reset_map_players, lms_ResetPlayers, CBC_ORDER_ANY); + MUTATOR_HOOK(PutClientInServer, lms_PlayerPreSpawn, CBC_ORDER_ANY); + MUTATOR_HOOK(PlayerSpawn, lms_PlayerSpawn, CBC_ORDER_ANY); + MUTATOR_HOOK(PlayerDies, lms_PlayerDies, 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_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; +} diff --git a/qcsrc/server/mutators/gamemode_lms.qh b/qcsrc/server/mutators/gamemode_lms.qh new file mode 100644 index 0000000000..508bf8c6cd --- /dev/null +++ b/qcsrc/server/mutators/gamemode_lms.qh @@ -0,0 +1,12 @@ +// 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(); + +// camp check +.float lms_nextcheck; +.float lms_traveled_distance; \ No newline at end of file diff --git a/qcsrc/server/mutators/gamemode_nexball.qc b/qcsrc/server/mutators/gamemode_nexball.qc index 62cfd01ad8..8790162afa 100644 --- a/qcsrc/server/mutators/gamemode_nexball.qc +++ b/qcsrc/server/mutators/gamemode_nexball.qc @@ -49,7 +49,7 @@ void nexball_setstatus(void) { if(self.ballcarried.teamtime && (self.ballcarried.teamtime < time)) { - bprint("The ", ColoredTeamName(self.team), " held the ball for too long.\n"); + bprint("The ", Team_ColoredFullName(self.team), " held the ball for too long.\n"); oldself = self; self = self.ballcarried; DropBall(self, self.owner.origin, '0 0 0'); @@ -204,7 +204,8 @@ void ResetBall(void) if(self.cnt < 2) // step 1 { if(time == self.teamtime) - bprint("The ", ColoredTeamName(self.team), " held the ball for too long.\n"); + bprint("The ", Team_ColoredFullName(self.team), " held the ball for too long.\n"); + self.touch = func_null; self.movetype = MOVETYPE_NOCLIP; self.velocity = '0 0 0'; // just in case? @@ -341,9 +342,9 @@ void GoalTouch(void) { LogNB("fault", ball.pusher); if(nb_teams == 2) - bprint(ColoredTeamName(otherteam), " gets a point due to ", pname, "^7's silliness.\n"); + bprint(Team_ColoredFullName(otherteam), " gets a point due to ", pname, "^7's silliness.\n"); else - bprint(ColoredTeamName(ball.team), " loses a point due to ", pname, "^7's silliness.\n"); + bprint(Team_ColoredFullName(ball.team), " loses a point due to ", pname, "^7's silliness.\n"); pscore = -1; } else if(self.team == GOAL_OUT) @@ -358,7 +359,7 @@ void GoalTouch(void) else //score { LogNB(strcat("goal:", ftos(self.team)), ball.pusher); - bprint("Goaaaaal! ", pname, "^7 scored a point for the ", ColoredTeamName(ball.team), ".\n"); + bprint("Goaaaaal! ", pname, "^7 scored a point for the ", Team_ColoredFullName(ball.team), ".\n"); pscore = 1; } @@ -424,28 +425,28 @@ void nb_spawnteams(void) { switch(e.team) { - case COLOR_TEAM1: + case NUM_TEAM_1: if(!t_r) { nb_spawnteam("Red", e.team-1) ; t_r = 1; } break; - case COLOR_TEAM2: + case NUM_TEAM_2: if(!t_b) { nb_spawnteam("Blue", e.team-1) ; t_b = 1; } break; - case COLOR_TEAM3: + case NUM_TEAM_3: if(!t_y) { nb_spawnteam("Yellow", e.team-1); t_y = 1; } break; - case COLOR_TEAM4: + case NUM_TEAM_4: if(!t_p) { nb_spawnteam("Pink", e.team-1) ; @@ -575,22 +576,22 @@ void SpawnGoal(void) void spawnfunc_nexball_redgoal(void) { - self.team = COLOR_TEAM1; + self.team = NUM_TEAM_1; SpawnGoal(); } void spawnfunc_nexball_bluegoal(void) { - self.team = COLOR_TEAM2; + self.team = NUM_TEAM_2; SpawnGoal(); } void spawnfunc_nexball_yellowgoal(void) { - self.team = COLOR_TEAM3; + self.team = NUM_TEAM_3; SpawnGoal(); } void spawnfunc_nexball_pinkgoal(void) { - self.team = COLOR_TEAM4; + self.team = NUM_TEAM_4; SpawnGoal(); } @@ -843,14 +844,8 @@ float w_nexball_weapon(float req) precache_sound("misc/typehit.wav"); } else if(req == WR_SETUP) - weapon_setup(WEP_PORTO); - else if(req == WR_SUICIDEMESSAGE) { - w_deathtypestring = "is a weirdo"; - } - else if(req == WR_KILLMESSAGE) - { - w_deathtypestring = "got killed by #'s black magic"; + weapon_setup(WEP_PORTO); } // No need to check WR_CHECKAMMO* or WR_AIM, it should always return TRUE return TRUE; diff --git a/qcsrc/server/mutators/gamemode_onslaught.qc b/qcsrc/server/mutators/gamemode_onslaught.qc index dd0152ed08..3801de302d 100644 --- a/qcsrc/server/mutators/gamemode_onslaught.qc +++ b/qcsrc/server/mutators/gamemode_onslaught.qc @@ -1,8 +1,8 @@ float autocvar_g_onslaught_spawn_at_controlpoints; float autocvar_g_onslaught_spawn_at_generator; -float autocvar_g_onslaught_controlpoints_proxycap; -float autocvar_g_onslaught_controlpoints_proxycap_distance = 512; -float autocvar_g_onslaught_controlpoints_proxycap_dps = 100; +float autocvar_g_onslaught_cp_proxydecap; +var float autocvar_g_onslaught_cp_proxydecap_distance = 512; +var float autocvar_g_onslaught_cp_proxydecap_dps = 100; void onslaught_generator_updatesprite(entity e); void onslaught_controlpoint_updatesprite(entity e); @@ -22,8 +22,6 @@ void onslaught_link_checkupdate(); .float lastshielded; .float lastcaptured; -.string model1, model2, model3; - entity ons_red_generator; entity ons_blue_generator; @@ -163,16 +161,16 @@ void onslaught_updatelinks() } if(l.goalentity.classname == "onslaught_generator") { - if(l.goalentity.team == COLOR_TEAM1) + if(l.goalentity.team == NUM_TEAM_1) l.enemy.isgenneighbor_red = TRUE; - else if(l.goalentity.team == COLOR_TEAM2) + else if(l.goalentity.team == NUM_TEAM_2) l.enemy.isgenneighbor_blue = TRUE; } else { - if(l.goalentity.team == COLOR_TEAM1) + if(l.goalentity.team == NUM_TEAM_1) l.enemy.iscpneighbor_red = TRUE; - else if(l.goalentity.team == COLOR_TEAM2) + else if(l.goalentity.team == NUM_TEAM_2) l.enemy.iscpneighbor_blue = TRUE; } } @@ -185,16 +183,16 @@ void onslaught_updatelinks() } if(l.enemy.classname == "onslaught_generator") { - if(l.enemy.team == COLOR_TEAM1) + if(l.enemy.team == NUM_TEAM_1) l.goalentity.isgenneighbor_red = TRUE; - else if(l.enemy.team == COLOR_TEAM2) + else if(l.enemy.team == NUM_TEAM_2) l.goalentity.isgenneighbor_blue = TRUE; } else { - if(l.enemy.team == COLOR_TEAM1) + if(l.enemy.team == NUM_TEAM_1) l.goalentity.iscpneighbor_red = TRUE; - else if(l.enemy.team == COLOR_TEAM2) + else if(l.enemy.team == NUM_TEAM_2) l.goalentity.iscpneighbor_blue = TRUE; } } @@ -254,10 +252,10 @@ void onslaught_updatelinks() { if (l.iscaptured) { - if (l.team == COLOR_TEAM1) t1 = 1; - if (l.team == COLOR_TEAM2) t2 = 1; - if (l.team == COLOR_TEAM3) t3 = 1; - if (l.team == COLOR_TEAM4) t4 = 1; + if (l.team == NUM_TEAM_1) t1 = 1; + if (l.team == NUM_TEAM_2) t2 = 1; + if (l.team == NUM_TEAM_3) t3 = 1; + if (l.team == NUM_TEAM_4) t4 = 1; } onslaught_generator_updatesprite(l); l = l.chain; @@ -271,14 +269,14 @@ void onslaught_updatelinks() float onslaught_controlpoint_can_be_linked(entity cp, float t) { - if(t == COLOR_TEAM1) + if(t == NUM_TEAM_1) { if(cp.isgenneighbor_red) return 2; if(cp.iscpneighbor_red) return 1; } - else if(t == COLOR_TEAM2) + else if(t == NUM_TEAM_2) { if(cp.isgenneighbor_blue) return 2; @@ -354,7 +352,7 @@ float onslaught_controlpoint_attackable(entity cp, float t) // if there's already an icon built, nothing happens if(cp.team == t) { - a = onslaught_controlpoint_can_be_linked(cp, COLOR_TEAM1 + COLOR_TEAM2 - t); + a = onslaught_controlpoint_can_be_linked(cp, NUM_TEAM_1 + NUM_TEAM_2 - t); if(a) // attackable by enemy? return -2; // EMERGENCY! return -1; @@ -371,7 +369,7 @@ float onslaught_controlpoint_attackable(entity cp, float t) // free point if(onslaught_controlpoint_can_be_linked(cp, t)) { - a = onslaught_controlpoint_can_be_linked(cp, COLOR_TEAM1 + COLOR_TEAM2 - t); + a = onslaught_controlpoint_can_be_linked(cp, NUM_TEAM_1 + NUM_TEAM_2 - t); if(a == 2) return 4; // GET THIS ONE NOW! else @@ -419,19 +417,19 @@ void onslaught_generator_think() } else if (overtime_msg_time) overtime_msg_time = 0; - + if(!self.isshielded && self.wait < time) { self.wait = time + 5; - FOR_EACH_PLAYER(e) + FOR_EACH_REALPLAYER(e) { if(e.team == self.team) { centerprint(e, "^1Your generator is NOT shielded!\n^7Re-capture controlpoints to shield it!"); soundto(MSG_ONE, e, CHAN_AUTO, "kh/alarm.wav", VOL_BASE, ATTN_NONE); // FIXME: Uniqe sound? - } - } - } + } + } + } } } @@ -596,7 +594,7 @@ void onslaught_generator_damage(entity inflictor, entity attacker, float damage, if (time > self.pain_finished) { self.pain_finished = time + 10; - bprint(ColoredTeamName(self.team), " generator under attack!\n"); + bprint(Team_ColoredFullName(self.team), " generator under attack!\n"); play2team(self.team, "onslaught/generator_underattack.wav"); } } @@ -612,19 +610,19 @@ void onslaught_generator_damage(entity inflictor, entity attacker, float damage, lh = ceil(self.lasthealth / 100) * 100; h = ceil(self.health / 100) * 100; if(lh != h) - bprint(ColoredTeamName(self.team), " generator has less than ", ftos(h), " health remaining\n"); + bprint(Team_ColoredFullName(self.team), " generator has less than ", ftos(h), " health remaining\n"); #endif self.lasthealth = self.health; } else if not(inWarmupStage) { if (attacker == self) - bprint(ColoredTeamName(self.team), " generator spontaneously exploded due to overtime!\n"); + bprint(Team_ColoredFullName(self.team), " generator spontaneously exploded due to overtime!\n"); else { string t; - t = ColoredTeamName(attacker.team); - bprint(ColoredTeamName(self.team), " generator destroyed by ", t, "!\n"); + t = Team_ColoredFullName(attacker.team); + bprint(Team_ColoredFullName(self.team), " generator destroyed by ", t, "!\n"); } self.iscaptured = FALSE; self.islinked = FALSE; @@ -706,16 +704,16 @@ string onslaught_generator_waypointsprite_for_team(entity e, float t) { if(t == e.team) { - if(e.team == COLOR_TEAM1) + if(e.team == NUM_TEAM_1) return "ons-gen-red"; - else if(e.team == COLOR_TEAM2) + else if(e.team == NUM_TEAM_2) return "ons-gen-blue"; } if(e.isshielded) return "ons-gen-shielded"; - if(e.team == COLOR_TEAM1) + if(e.team == NUM_TEAM_1) return "ons-gen-red"; - else if(e.team == COLOR_TEAM2) + else if(e.team == NUM_TEAM_2) return "ons-gen-blue"; return ""; } @@ -723,8 +721,8 @@ string onslaught_generator_waypointsprite_for_team(entity e, float t) void onslaught_generator_updatesprite(entity e) { string s1, s2, s3; - s1 = onslaught_generator_waypointsprite_for_team(e, COLOR_TEAM1); - s2 = onslaught_generator_waypointsprite_for_team(e, COLOR_TEAM2); + s1 = onslaught_generator_waypointsprite_for_team(e, NUM_TEAM_1); + s2 = onslaught_generator_waypointsprite_for_team(e, NUM_TEAM_2); s3 = onslaught_generator_waypointsprite_for_team(e, -1); WaypointSprite_UpdateSprites(e.sprite, s1, s2, s3); @@ -734,14 +732,14 @@ void onslaught_generator_updatesprite(entity e) e.lastshielded = e.isshielded; if(e.lastshielded) { - if(e.team == COLOR_TEAM1 || e.team == COLOR_TEAM2) + if(e.team == NUM_TEAM_1 || e.team == NUM_TEAM_2) WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, 0.5 * colormapPaletteColor(e.team - 1, FALSE)); else WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.5 0.5 0.5'); } else { - if(e.team == COLOR_TEAM1 || e.team == COLOR_TEAM2) + if(e.team == NUM_TEAM_1 || e.team == NUM_TEAM_2) WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, colormapPaletteColor(e.team - 1, FALSE)); else WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.75 0.75 0.75'); @@ -758,25 +756,25 @@ string onslaught_controlpoint_waypointsprite_for_team(entity e, float t) a = onslaught_controlpoint_attackable(e, t); if(a == 3 || a == 4) // ATTACK/TOUCH THIS ONE NOW { - if(e.team == COLOR_TEAM1) + if(e.team == NUM_TEAM_1) return "ons-cp-atck-red"; - else if(e.team == COLOR_TEAM2) + else if(e.team == NUM_TEAM_2) return "ons-cp-atck-blue"; else return "ons-cp-atck-neut"; } else if(a == -2) // DEFEND THIS ONE NOW { - if(e.team == COLOR_TEAM1) + if(e.team == NUM_TEAM_1) return "ons-cp-dfnd-red"; - else if(e.team == COLOR_TEAM2) + else if(e.team == NUM_TEAM_2) return "ons-cp-dfnd-blue"; } else if(e.team == t || a == -1 || a == 1) // own point, or fire at it { - if(e.team == COLOR_TEAM1) + if(e.team == NUM_TEAM_1) return "ons-cp-red"; - else if(e.team == COLOR_TEAM2) + else if(e.team == NUM_TEAM_2) return "ons-cp-blue"; } else if(a == 2) // touch it @@ -784,9 +782,9 @@ string onslaught_controlpoint_waypointsprite_for_team(entity e, float t) } else { - if(e.team == COLOR_TEAM1) + if(e.team == NUM_TEAM_1) return "ons-cp-red"; - else if(e.team == COLOR_TEAM2) + else if(e.team == NUM_TEAM_2) return "ons-cp-blue"; else return "ons-cp-neut"; @@ -797,13 +795,13 @@ string onslaught_controlpoint_waypointsprite_for_team(entity e, float t) void onslaught_controlpoint_updatesprite(entity e) { string s1, s2, s3; - s1 = onslaught_controlpoint_waypointsprite_for_team(e, COLOR_TEAM1); - s2 = onslaught_controlpoint_waypointsprite_for_team(e, COLOR_TEAM2); + s1 = onslaught_controlpoint_waypointsprite_for_team(e, NUM_TEAM_1); + s2 = onslaught_controlpoint_waypointsprite_for_team(e, NUM_TEAM_2); s3 = onslaught_controlpoint_waypointsprite_for_team(e, -1); WaypointSprite_UpdateSprites(e.sprite, s1, s2, s3); float sh; - sh = !(onslaught_controlpoint_can_be_linked(e, COLOR_TEAM1) || onslaught_controlpoint_can_be_linked(e, COLOR_TEAM2)); + sh = !(onslaught_controlpoint_can_be_linked(e, NUM_TEAM_1) || onslaught_controlpoint_can_be_linked(e, NUM_TEAM_2)); if(e.lastteam != e.team + 2 || e.lastshielded != sh || e.iscaptured != e.lastcaptured) { @@ -821,14 +819,14 @@ void onslaught_controlpoint_updatesprite(entity e) } if(e.lastshielded) { - if(e.team == COLOR_TEAM1 || e.team == COLOR_TEAM2) + if(e.team == NUM_TEAM_1 || e.team == NUM_TEAM_2) WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, 0.5 * colormapPaletteColor(e.team - 1, FALSE)); else WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.5 0.5 0.5'); } else { - if(e.team == COLOR_TEAM1 || e.team == COLOR_TEAM2) + if(e.team == NUM_TEAM_1 || e.team == NUM_TEAM_2) WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, colormapPaletteColor(e.team - 1, FALSE)); else WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.75 0.75 0.75'); @@ -856,8 +854,11 @@ void onslaught_generator_reset() setmodel(self, "models/onslaught/generator.md3"); setsize(self, '-52 -52 -14', '52 52 75'); - if (!self.noalign) - droptofloor(); + if(!self.noalign) + { + setorigin(self, self.origin + '0 0 20'); + droptofloor(); + } WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health); WaypointSprite_UpdateHealth(self.sprite, self.health); @@ -910,10 +911,10 @@ void spawnfunc_onslaught_generator() if (!self.team) objerror("team must be set"); - if(self.team == COLOR_TEAM1) + if(self.team == NUM_TEAM_1) ons_red_generator = self; - if(self.team == COLOR_TEAM2) + if(self.team == NUM_TEAM_2) ons_blue_generator = self; self.team_saved = self.team; @@ -948,7 +949,7 @@ void spawnfunc_onslaught_generator() InitializeEntity(self, onslaught_generator_delayed, INITPRIO_LAST); WaypointSprite_SpawnFixed(string_null, self.origin + '0 0 128', self, sprite, RADARICON_NONE, '0 0 0'); - WaypointSprite_UpdateRule(self.sprite, COLOR_TEAM2, SPRITERULE_TEAMPLAY); + WaypointSprite_UpdateRule(self.sprite, NUM_TEAM_2, SPRITERULE_TEAMPLAY); WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health); WaypointSprite_UpdateHealth(self.sprite, self.health); @@ -988,7 +989,7 @@ void onslaught_controlpoint_icon_damage(entity inflictor, entity attacker, float if (attacker.classname == "player") { nag = FALSE; - if(self.team == COLOR_TEAM1) + if(self.team == NUM_TEAM_1) { if(time - ons_notification_time_team1 > 10) { @@ -996,7 +997,7 @@ void onslaught_controlpoint_icon_damage(entity inflictor, entity attacker, float ons_notification_time_team1 = time; } } - else if(self.team == COLOR_TEAM2) + else if(self.team == NUM_TEAM_2) { if(time - ons_notification_time_team2 > 10) { @@ -1035,8 +1036,8 @@ void onslaught_controlpoint_icon_damage(entity inflictor, entity attacker, float pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1); { string t; - t = ColoredTeamName(attacker.team); - bprint(ColoredTeamName(self.team), " ", self.message, " control point destroyed by ", t, "\n"); + t = Team_ColoredFullName(attacker.team); + bprint(Team_ColoredFullName(self.team), " ", self.message, " control point destroyed by ", t, "\n"); ons_throwgib(self.origin, (2 * randomvec() - '1 1 1') * 25, "models/onslaught/controlpoint_icon_gib1.md3", 3, FALSE); ons_throwgib(self.origin, (2 * randomvec() - '1 1 1') * 45, "models/onslaught/controlpoint_icon_gib2.md3", 3, FALSE); ons_throwgib(self.origin, (2 * randomvec() - '1 1 1') * 45, "models/onslaught/controlpoint_icon_gib2.md3", 3, FALSE); @@ -1076,9 +1077,9 @@ void onslaught_controlpoint_icon_think() { entity oself; self.nextthink = time + sys_frametime; - - if(autocvar_g_onslaught_controlpoints_proxycap) - { + + if(autocvar_g_onslaught_cp_proxydecap) + { float _enemy_count = 0; float _friendly_count = 0; float _dist; @@ -1089,7 +1090,7 @@ void onslaught_controlpoint_icon_think() if(!_player.deadflag) { _dist = vlen(_player.origin - self.origin); - if(_dist < autocvar_g_onslaught_controlpoints_proxycap_distance) + if(_dist < autocvar_g_onslaught_cp_proxydecap_distance) { if(_player.team == self.team) ++_friendly_count; @@ -1099,9 +1100,9 @@ void onslaught_controlpoint_icon_think() } } - _friendly_count = _friendly_count * (autocvar_g_onslaught_controlpoints_proxycap_dps * sys_frametime); - _enemy_count = _enemy_count * (autocvar_g_onslaught_controlpoints_proxycap_dps * sys_frametime); - + _friendly_count = _friendly_count * (autocvar_g_onslaught_cp_proxydecap_dps * sys_frametime); + _enemy_count = _enemy_count * (autocvar_g_onslaught_cp_proxydecap_dps * sys_frametime); + self.health = bound(0, self.health + (_friendly_count - _enemy_count), self.max_health); if(self.health <= 0) { @@ -1109,7 +1110,7 @@ void onslaught_controlpoint_icon_think() return; } } - + if (time > self.pain_finished + 5) { if(self.health < self.max_health) @@ -1234,7 +1235,7 @@ void onslaught_controlpoint_icon_buildthink() self.count = autocvar_g_onslaught_cp_regen * sys_frametime; // slow repair rate from now on self.think = onslaught_controlpoint_icon_think; sound(self, CH_TRIGGER, "onslaught/controlpoint_built.wav", VOL_BASE, ATTN_NORM); - bprint(ColoredTeamName(self.team), " captured ", self.owner.message, " control point\n"); + bprint(Team_ColoredFullName(self.team), " captured ", self.owner.message, " control point\n"); self.owner.iscaptured = TRUE; WaypointSprite_UpdateMaxHealth(self.owner.sprite, self.max_health); @@ -1338,49 +1339,6 @@ keys: "target" - target any entities that are tied to this control point, such as vehicles and buildable structure entities. "message" - name of this control point (should reflect the location in the map, such as "center bridge", "north tower", etc) */ - - /* -void onslaught_controlpoint_think() -{ - self.nextthink = time; - //if(autocvar_g_onslaught_controlpoints_proxycap) - - float _enemy_count; - float _friendly_count; - float _dist; - entity _player; - - FOR_EACH_PLAYER(_player) - { - if(!_player.deadflag) - { - _dist = vlen(_player.origin - self.origin); - if(_dist < autocvar_g_onslaught_controlpoints_proxycap_distance) - { - if(_player.team == self.team) - ++_friendly_count; - else - ++_enemy_count; - } - } - } - - _friendly_count = _friendly_count * (autocvar_g_onslaught_controlpoints_proxycap_dps * sys_frametime); - _enemy_count = _enemy_count * (autocvar_g_onslaught_controlpoints_proxycap_dps * sys_frametime); - - self.health = bound(0, self.health + (_friendly_count - _enemy_count), self.max_health); - if(self.health <= 0) - { - onslaught_controlpoint_icon_damage(self, self, 1, 0, self.origin, '0 0 0'); - return; - } - - if(self.health == max_health) - { - - } -} -*/ void spawnfunc_onslaught_controlpoint() { @@ -1407,20 +1365,23 @@ void spawnfunc_onslaught_controlpoint() precache_sound("onslaught/controlpoint_underattack.wav"); precache_sound("onslaught/ons_spark1.wav"); precache_sound("onslaught/ons_spark2.wav"); + self.solid = SOLID_BBOX; self.movetype = MOVETYPE_NONE; setmodel(self, "models/onslaught/controlpoint_pad.md3"); //setsize(self, '-32 -32 0', '32 32 8'); - if (!self.noalign) - droptofloor(); - - setorigin(self, self.origin); + if(!self.noalign) + { + setorigin(self, self.origin + '0 0 20'); + droptofloor(); + } self.touch = onslaught_controlpoint_touch; self.team = 0; self.colormap = 1024; self.iscaptured = FALSE; self.islinked = FALSE; self.isshielded = TRUE; + // spawn shield model which indicates whether this can be damaged self.enemy = spawn(); self.enemy.classname = "onslaught_controlpoint_shield"; @@ -1428,7 +1389,7 @@ void spawnfunc_onslaught_controlpoint() self.enemy.movetype = MOVETYPE_NONE; self.enemy.effects = EF_ADDITIVE; setmodel(self.enemy , "models/onslaught/controlpoint_shield.md3"); - + setattachment(self.enemy , self, ""); //setsize(e, '-32 -32 0', '32 32 128'); @@ -1438,10 +1399,10 @@ void spawnfunc_onslaught_controlpoint() waypoint_spawnforitem(self); WaypointSprite_SpawnFixed(string_null, self.origin + '0 0 128', self, sprite, RADARICON_NONE, '0 0 0'); - WaypointSprite_UpdateRule(self.sprite, COLOR_TEAM2, SPRITERULE_TEAMPLAY); + WaypointSprite_UpdateRule(self.sprite, NUM_TEAM_2, SPRITERULE_TEAMPLAY); onslaught_updatelinks(); - + self.reset = onslaught_controlpoint_reset; } @@ -1476,28 +1437,28 @@ void onslaught_link_checkupdate() redpower = bluepower = 0; if(self.goalentity.islinked) { - if(self.goalentity.team == COLOR_TEAM1) + if(self.goalentity.team == NUM_TEAM_1) redpower = 1; - else if(self.goalentity.team == COLOR_TEAM2) + else if(self.goalentity.team == NUM_TEAM_2) bluepower = 1; } if(self.enemy.islinked) { - if(self.enemy.team == COLOR_TEAM1) + if(self.enemy.team == NUM_TEAM_1) redpower = 2; - else if(self.enemy.team == COLOR_TEAM2) + else if(self.enemy.team == NUM_TEAM_2) bluepower = 2; } float cc; if(redpower == 1 && bluepower == 2) - cc = (COLOR_TEAM1 - 1) * 0x01 + (COLOR_TEAM2 - 1) * 0x10; + cc = (NUM_TEAM_1 - 1) * 0x01 + (NUM_TEAM_2 - 1) * 0x10; else if(redpower == 2 && bluepower == 1) - cc = (COLOR_TEAM1 - 1) * 0x10 + (COLOR_TEAM2 - 1) * 0x01; + cc = (NUM_TEAM_1 - 1) * 0x10 + (NUM_TEAM_2 - 1) * 0x01; else if(redpower) - cc = (COLOR_TEAM1 - 1) * 0x11; + cc = (NUM_TEAM_1 - 1) * 0x11; else if(bluepower) - cc = (COLOR_TEAM2 - 1) * 0x11; + cc = (NUM_TEAM_2 - 1) * 0x11; else cc = 0; @@ -1557,7 +1518,7 @@ MUTATOR_HOOKFUNCTION(ons_BuildMutatorsString) MUTATOR_HOOKFUNCTION(ons_BuildMutatorsPrettyString) { - ret_string = strcat(ret_string, ", Onslught"); + ret_string = strcat(ret_string, ", Onslaught"); return 0; } @@ -1569,10 +1530,10 @@ MUTATOR_HOOKFUNCTION(ons_Spawn_Score) RandomSelection_Init(); - if(self.team == COLOR_TEAM1) + if(self.team == NUM_TEAM_1) RandomSelection_Add(ons_red_generator, 0, string_null, 1, 1); - if(self.team == COLOR_TEAM2) + if(self.team == NUM_TEAM_2) RandomSelection_Add(ons_blue_generator, 0, string_null, 1, 1); entity _cp = findchain(classname, "onslaught_controlpoint"): @@ -1611,7 +1572,7 @@ MUTATOR_HOOKFUNCTION(ons_PlayerSpawn) RandomSelection_Init(); - if(self.team == COLOR_TEAM1) + if(self.team == NUM_TEAM_1) { if(!_close_to_home) _trg_gen = ons_blue_generator; @@ -1619,7 +1580,7 @@ MUTATOR_HOOKFUNCTION(ons_PlayerSpawn) _trg_gen = ons_red_generator; } - if(self.team == COLOR_TEAM2) + if(self.team == NUM_TEAM_2) { if(_close_to_home) _trg_gen = ons_blue_generator; @@ -1664,7 +1625,7 @@ MUTATOR_HOOKFUNCTION(ons_PlayerSpawn) if(!autocvar_g_onslaught_spawn_at_generator) return 0; - _trg_gen = ((self.team == COLOR_TEAM1) ? ons_red_generator : ons_blue_generator); + _trg_gen = ((self.team == NUM_TEAM_1) ? ons_red_generator : ons_blue_generator); for(i = 0; i < 10; ++i) { @@ -1685,15 +1646,11 @@ MUTATOR_HOOKFUNCTION(ons_PlayerSpawn) MUTATOR_DEFINITION(gamemode_onslaught) { - //MUTATOR_HOOK(PlayerDies, nexball_BallDrop, CBC_ORDER_ANY); - //MUTATOR_HOOK(MakePlayerObserver, nexball_BallDrop, CBC_ORDER_ANY); - //MUTATOR_HOOK(ClientDisconnect, nexball_BallDrop, CBC_ORDER_ANY); - //MUTATOR_HOOK(PlayerPreThink, nexball_PlayerPreThink, CBC_ORDER_ANY); MUTATOR_HOOK(BuildMutatorsPrettyString, ons_BuildMutatorsPrettyString, CBC_ORDER_ANY); MUTATOR_HOOK(BuildMutatorsString, ons_BuildMutatorsString, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerSpawn, ons_PlayerSpawn, CBC_ORDER_ANY); //MUTATOR_HOOK(Spawn_Score, ons_Spawn_Score, CBC_ORDER_ANY); - + MUTATOR_ONADD { if(time > 1) // game loads at time 1 diff --git a/qcsrc/server/mutators/mutator_new_toys.qc b/qcsrc/server/mutators/mutator_new_toys.qc index 6ee3e87b3c..89ad13c538 100644 --- a/qcsrc/server/mutators/mutator_new_toys.qc +++ b/qcsrc/server/mutators/mutator_new_toys.qc @@ -184,7 +184,7 @@ MUTATOR_HOOKFUNCTION(nt_SetWeaponreplace) 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; } @@ -200,7 +200,7 @@ MUTATOR_DEFINITION(mutator_new_toys) 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; diff --git a/qcsrc/server/mutators/mutator_nix.qc b/qcsrc/server/mutators/mutator_nix.qc index b492ee60eb..d5f95bd303 100644 --- a/qcsrc/server/mutators/mutator_nix.qc +++ b/qcsrc/server/mutators/mutator_nix.qc @@ -96,7 +96,7 @@ void NIX_GiveCurrentWeapon() if(dt >= 1 && dt <= 5) self.nix_lastinfotime = -42; else - Send_CSQC_Centerprint_Generic(self, CPID_NIX_WPNCHANGE, strcat("^2Active weapon: ^3", W_Name(nix_weapon)), 0, 0); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon); weapon_action(nix_weapon, WR_RESETPLAYER); @@ -118,7 +118,7 @@ void NIX_GiveCurrentWeapon() { self.nix_lastinfotime = dt; // initial value 0 should count as "not seen" if(dt >= 1 && dt <= 5) - Send_CSQC_Centerprint_Generic(self, CPID_NIX_WPNCHANGE, strcat("^3%d^2 seconds until weapon change...\n\nNext weapon: ^3", W_Name(nix_nextweapon)), 1, dt); + Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt); } if(!(self.items & IT_UNLIMITED_WEAPON_AMMO) && time > self.nix_nextincr) diff --git a/qcsrc/server/mutators/mutator_superspec.qc b/qcsrc/server/mutators/mutator_superspec.qc index 0645b48054..8f289e5c3b 100644 --- a/qcsrc/server/mutators/mutator_superspec.qc +++ b/qcsrc/server/mutators/mutator_superspec.qc @@ -21,7 +21,7 @@ float _spectate(entity _player) { - if(SpectateNext(_player) == 1) + if(Spectate(_player) == 1) { PutObserverInServer(); self.classname = "spectator"; @@ -392,9 +392,9 @@ MUTATOR_HOOKFUNCTION(superspec_SV_ParseClientCommand) if(cmd_argc == 2) { if(argv(1) == "red") - _team = COLOR_TEAM1; + _team = NUM_TEAM_1; else - _team = COLOR_TEAM2; + _team = NUM_TEAM_2; } FOR_EACH_PLAYER(_player) @@ -443,6 +443,9 @@ void superspec_hello() MUTATOR_HOOKFUNCTION(superspec_ClientConnect) { + if(clienttype(self) != CLIENTTYPE_REAL) + return FALSE; + string fn = "superspec-local.options"; float fh; diff --git a/qcsrc/server/mutators/mutator_touchexplode.qc b/qcsrc/server/mutators/mutator_touchexplode.qc new file mode 100644 index 0000000000..f51ed653a0 --- /dev/null +++ b/qcsrc/server/mutators/mutator_touchexplode.qc @@ -0,0 +1,46 @@ +.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; +} diff --git a/qcsrc/server/mutators/mutators.qh b/qcsrc/server/mutators/mutators.qh index 4bdcbb2823..dab42bd65d 100644 --- a/qcsrc/server/mutators/mutators.qh +++ b/qcsrc/server/mutators/mutators.qh @@ -1,3 +1,6 @@ +MUTATOR_DECLARATION(gamemode_assault); +MUTATOR_DECLARATION(gamemode_arena); +MUTATOR_DECLARATION(gamemode_ca); MUTATOR_DECLARATION(gamemode_keyhunt); MUTATOR_DECLARATION(gamemode_freezetag); MUTATOR_DECLARATION(gamemode_keepaway); @@ -5,6 +8,7 @@ MUTATOR_DECLARATION(gamemode_ctf); MUTATOR_DECLARATION(gamemode_nexball); MUTATOR_DECLARATION(gamemode_onslaught); MUTATOR_DECLARATION(gamemode_domination); +MUTATOR_DECLARATION(gamemode_lms); MUTATOR_DECLARATION(mutator_dodging); MUTATOR_DECLARATION(mutator_invincibleprojectiles); @@ -15,5 +19,6 @@ MUTATOR_DECLARATION(mutator_spawn_near_teammate); MUTATOR_DECLARATION(mutator_physical_items); MUTATOR_DECLARATION(mutator_vampire); MUTATOR_DECLARATION(mutator_superspec); +MUTATOR_DECLARATION(mutator_touchexplode); MUTATOR_DECLARATION(sandbox); diff --git a/qcsrc/server/mutators/sandbox.qc b/qcsrc/server/mutators/sandbox.qc index 391e317423..cf5d82f87a 100644 --- a/qcsrc/server/mutators/sandbox.qc +++ b/qcsrc/server/mutators/sandbox.qc @@ -26,7 +26,7 @@ void sandbox_ObjectFunction_Touch() 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 } @@ -403,7 +403,7 @@ void sandbox_Database_Load() { // 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) @@ -675,7 +675,7 @@ MUTATOR_HOOKFUNCTION(sandbox_PlayerCommand) 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 diff --git a/qcsrc/server/portals.qc b/qcsrc/server/portals.qc index 3e83c972ee..f0b9c5b218 100644 --- a/qcsrc/server/portals.qc +++ b/qcsrc/server/portals.qc @@ -172,7 +172,7 @@ float Portal_TeleportPlayer(entity teleporter, entity player) { // 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) diff --git a/qcsrc/server/progs.src b/qcsrc/server/progs.src index db93116109..b3cc22ddaa 100644 --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@ -13,7 +13,9 @@ sys-post.qh ../warpzonelib/server.qh ../common/constants.qh +../common/teams.qh ../common/util.qh +../common/counting.qh ../common/items.qh ../common/explosion_equation.qh ../common/urllib.qh @@ -28,13 +30,20 @@ autocvars.qh constants.qh defs.qh // Should rename this, it has fields and globals +../common/notifications.qh // must be after autocvars +../common/deathtypes.qh // must be after notifications + 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 //// @@ -80,6 +89,8 @@ antilag.qh playerdemo.qh +round_handler.qh + // singleplayer stuff item_key.qh secret.qh @@ -96,8 +107,7 @@ g_subs.qc g_tetris.qc -runematch.qc -arena.qc +//runematch.qc g_violence.qc g_damage.qc @@ -168,7 +178,7 @@ command/getreplies.qc command/cmd.qc command/sv_cmd.qc -assault.qc +//assault.qc ipban.qc @@ -206,9 +216,14 @@ anticheat.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 @@ -216,6 +231,7 @@ mutators/gamemode_keyhunt.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 @@ -226,6 +242,7 @@ mutators/mutator_spawn_near_teammate.qc mutators/mutator_physical_items.qc mutators/sandbox.qc mutators/mutator_superspec.qc +mutators/mutator_touchexplode.qc ../warpzonelib/anglestransform.qc ../warpzonelib/mathlib.qc @@ -235,5 +252,6 @@ mutators/mutator_superspec.qc ../common/animdecide.qc ../common/util.qc +../common/notifications.qc ../common/if-this-file-errors-scroll-up-and-fix-the-warnings.fteqccfail diff --git a/qcsrc/server/race.qc b/qcsrc/server/race.qc index 2742888b61..6ec8a68e49 100644 --- a/qcsrc/server/race.qc +++ b/qcsrc/server/race.qc @@ -149,20 +149,17 @@ void race_setTime(string map, float t, string myuid, string mynetname, entity e) } float oldrec; - string recorddifference, oldrec_holder; + string oldrec_holder; if (player_prevpos && (player_prevpos < newpos || !newpos)) { oldrec = race_readTime(GetMapname(), player_prevpos); - recorddifference = strcat(" ^1[+", TIME_ENCODED_TOSTRING(t - oldrec), "]"); - bprint(mynetname, "^7 couldn't break their ", race_placeName(player_prevpos), " place record of ", TIME_ENCODED_TOSTRING(oldrec), recorddifference, "\n"); race_SendStatus(0, e); // "fail" - Send_KillNotification(e.netname, TIME_ENCODED_TOSTRING(t), "", RACE_FAIL, MSG_RACE); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_FAIL_RANKED, mynetname, player_prevpos, t, oldrec); return; } else if (!newpos) { // no ranking, time worse than the worst ranked - recorddifference = strcat(" ^1[+", TIME_ENCODED_TOSTRING(t - race_readTime(GetMapname(), RANKINGS_CNT)), "]"); - bprint(mynetname, "^7 couldn't break the ", race_placeName(RANKINGS_CNT), " place record of ", TIME_ENCODED_TOSTRING(race_readTime(GetMapname(), RANKINGS_CNT)), recorddifference, "\n"); + oldrec = race_readTime(GetMapname(), RANKINGS_CNT); race_SendStatus(0, e); // "fail" - Send_KillNotification(e.netname, TIME_ENCODED_TOSTRING(t), "", RACE_FAIL, MSG_RACE); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_FAIL_UNRANKED, mynetname, RANKINGS_CNT, t, oldrec); return; } @@ -171,7 +168,7 @@ void race_setTime(string map, float t, string myuid, string mynetname, entity e) // if the player does not have a UID we can unfortunately not store the record, as the rankings system relies on UIDs if(myuid == "") { - bprint(mynetname, "^1 scored a new record with ^7", TIME_ENCODED_TOSTRING(t), "^1, but lacks a UID, so the record will unfortunately be lost.\n"); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_NEW_MISSING_UID, mynetname, t); return; } @@ -190,34 +187,24 @@ void race_setTime(string map, float t, string myuid, string mynetname, entity e) if(rankings_reply) strunzone(rankings_reply); rankings_reply = strzone(getrankings()); - if(newpos == 1) { - if(newpos == player_prevpos) { - recorddifference = strcat(" ^2[-", TIME_ENCODED_TOSTRING(oldrec - t), "]"); - bprint(mynetname, "^1 improved their 1st place record with ", TIME_ENCODED_TOSTRING(t), recorddifference, "\n"); - } else if (oldrec == 0) { - bprint(mynetname, "^1 set the 1st place record with ", TIME_ENCODED_TOSTRING(t), "\n"); - } else { - recorddifference = strcat(" ^2[-", TIME_ENCODED_TOSTRING(oldrec - t), "]"); - bprint(mynetname, "^1 broke ", oldrec_holder, "^1's 1st place record with ", strcat(TIME_ENCODED_TOSTRING(t), recorddifference, "\n")); - } - race_SendStatus(3, e); // "new server record" - Send_KillNotification(e.netname, TIME_ENCODED_TOSTRING(t), "", RACE_SERVER_RECORD, MSG_RACE); - } else { - if(newpos == player_prevpos) { - recorddifference = strcat(" ^2[-", TIME_ENCODED_TOSTRING(oldrec - t), "]"); - bprint(mynetname, "^5 improved their ", race_placeName(newpos), " ^5place record with ", TIME_ENCODED_TOSTRING(t), recorddifference, "\n"); - race_SendStatus(1, e); // "new time" - Send_KillNotification(e.netname, TIME_ENCODED_TOSTRING(t), "", RACE_NEW_TIME, MSG_RACE); - } else if (oldrec == 0) { - bprint(mynetname, "^2 set the ", race_placeName(newpos), " ^2place record with ", TIME_ENCODED_TOSTRING(t), "\n"); - race_SendStatus(2, e); // "new rank" - Send_KillNotification(e.netname, TIME_ENCODED_TOSTRING(t), "", RACE_NEW_RANK, MSG_RACE); - } else { - recorddifference = strcat(" ^2[-", TIME_ENCODED_TOSTRING(oldrec - t), "]"); - bprint(mynetname, "^2 broke ", oldrec_holder, "^2's ", race_placeName(newpos), " ^2place record with ", strcat(TIME_ENCODED_TOSTRING(t), recorddifference, "\n")); - race_SendStatus(2, e); // "new rank" - Send_KillNotification(e.netname, TIME_ENCODED_TOSTRING(t), "", RACE_NEW_TIME, MSG_RACE); - } + + if(newpos == player_prevpos) + { + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_NEW_IMPROVED, mynetname, newpos, t, oldrec); + if(newpos == 1) { race_SendStatus(3, e); } // "new server record" + else { race_SendStatus(1, e); } // "new time" + } + else if(oldrec == 0) + { + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_NEW_SET, mynetname, newpos, t); + if(newpos == 1) { race_SendStatus(3, e); } // "new server record" + else { race_SendStatus(2, e); } // "new rank" + } + else + { + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_NEW_BROKEN, mynetname, oldrec_holder, newpos, t, oldrec); + if(newpos == 1) { race_SendStatus(3, e); } // "new server record" + else { race_SendStatus(2, e); } // "new rank" } } @@ -290,7 +277,7 @@ void race_SendTime(entity e, float cp, float t, float tvalid) { e.race_completed = 1; MAKE_INDEPENDENT_PLAYER(e); - bprint(e.netname, "^7 has finished the race.\n"); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_FINISHED, e.netname); ClientData_Touch(e); } } @@ -907,7 +894,7 @@ void race_AbandonRaceCheck(entity p) { p.race_completed = 1; MAKE_INDEPENDENT_PLAYER(p); - bprint(p.netname, "^7 has abandoned the race.\n"); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_ABANDONED, p.netname); ClientData_Touch(p); } } diff --git a/qcsrc/server/round_handler.qc b/qcsrc/server/round_handler.qc new file mode 100644 index 0000000000..af69e8e9e5 --- /dev/null +++ b/qcsrc/server/round_handler.qc @@ -0,0 +1,116 @@ +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; +} + diff --git a/qcsrc/server/round_handler.qh b/qcsrc/server/round_handler.qh new file mode 100644 index 0000000000..22a91dc2c6 --- /dev/null +++ b/qcsrc/server/round_handler.qh @@ -0,0 +1,23 @@ +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) + diff --git a/qcsrc/server/runematch.qc b/qcsrc/server/runematch.qc deleted file mode 100644 index ba8f648c88..0000000000 --- a/qcsrc/server/runematch.qc +++ /dev/null @@ -1,604 +0,0 @@ -float rune_numspawns; - -float RUNE_FIRST = 1; -float RUNE_STRENGTH = 1; -float RUNE_DEFENSE = 2; -float RUNE_REGEN = 4; -float RUNE_SPEED = 8; -float RUNE_VAMPIRE = 16; -float RUNE_LAST = 16; - -float CURSE_FIRST = 8192; -float CURSE_WEAK = 8192; -float CURSE_VULNER = 16384; -float CURSE_VENOM = 32768; -float CURSE_SLOW = 65536; -float CURSE_EMPATHY = 131072; -float CURSE_LAST = 131072; - -float RUNE_COUNT = 5; - -/* rune ideas: - - Doom/Death - Rune: When you damage enemies, you have a slight chance of instant-killing them (porportional to damage dealt / their health) - Curse: When you are damaged, you have a chance of being instant-killed - - Vengence/Slothful - Rune: The lower your health below 100, the more damage you deal (does not decrease your damage if you're above 100) - Curse: The higher your health (up to 100), the less damage you deal (at 100 hp deal 1/5th damage) - -*/ - -/*QUAKED spawnfunc_runematch_spawn_point (1 0 0) (-16 -16 -24) (16 16 24) -spawn point for runes in runematch -*/ - -void spawnfunc_runematch_spawn_point() -{ - if(!g_runematch || !autocvar_g_runematch_fixedspawns) - { - remove(self); - return; - } - - setsize(self, '0 0 -35', '0 0 0'); - droptofloor(); - ++rune_numspawns; -} - -// only used if using rune spawns at all -entity rune_find_spawnpoint() -{ - entity e; - - if(rune_numspawns < RUNE_COUNT) - return world; - - RandomSelection_Init(); - - for(e = world; (e = find(e, classname, "runematch_spawn_point")); ) - if(e.owner == world) - RandomSelection_Add(e, 0, string_null, e.cnt, 0); - - return RandomSelection_chosen_ent; -} - -float rune_spawn_somewhere(entity e) -{ - entity spot; - spot = rune_find_spawnpoint(); - if(spot) - { - spot.owner = e; - setorigin(e, spot.origin); - - e.owner = spot; - spot.owner = e; - - return TRUE; - } - else - { - if(MoveToRandomMapLocation(e, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256)) - { - // great - makevectors(self.angles), - self.velocity = v_forward * 250; - self.angles = '0 0 0'; - return TRUE; - } - else - { - // sorry, can't spawn, better luck next frame - return FALSE; - } - } -} - -void rune_unmark_spot(entity e) -{ - if(e.owner.classname == "runematch_spawn_point") - { - e.owner.owner = world; - e.owner = world; - } -} - -string RuneName(float r) -{ - if(r == RUNE_STRENGTH) - return "^1Strength^7"; - if(r == RUNE_DEFENSE) - return "^4Defense^7"; - if(r == RUNE_REGEN) - return "^2Vitality^7"; - if(r == RUNE_SPEED) - return "^3Speed^7"; - if(r == RUNE_VAMPIRE) - return "^6Vampire^7"; - - if(r == CURSE_WEAK) - return "^1Weakness^7"; - if(r == CURSE_VULNER) - return "^4Vulnerability^7"; - if(r == CURSE_VENOM) - return "^2Venom^7"; - if(r == CURSE_SLOW) - return "^3Slow^7"; - if(r == CURSE_EMPATHY) - return "^6Empathy^7"; - return strcat("^8[unnamed", ftos(r), "]^7"); -} - -vector RuneColormod(float r) -{ - vector _color = '255 0 255'; - - if(r == RUNE_STRENGTH) - _color = '255 0 0'; - if(r == RUNE_DEFENSE) - _color = '0 0 255';//'0 102 255';// - if(r == RUNE_REGEN) - _color = '0 204 0';//'0 255 0'; - if(r == RUNE_SPEED) - _color = 0.35*'185 185 0';//255 230 0';//'255 255 0'; - if(r == RUNE_VAMPIRE) - _color = '64 0 128';//'108 0 217';//'128 0 255';//'179 0 204';// - - if(r == CURSE_WEAK) - _color = '255 0 0'; - if(r == CURSE_VULNER) - _color = '0 0 255';//'0 102 255';// - if(r == CURSE_VENOM) - _color = '0 204 0';//'0 255 0'; - if(r == CURSE_SLOW) - _color = 0.5*'185 185 0';//'255 255 0'; - if(r == CURSE_EMPATHY) - _color = '179 0 204';//'128 0 255'; - - return _color * (1 / 255) * autocvar_g_runematch_rune_color_strength; -} - -void rune_respawn(); - -void RuneCarriedThink() -{ - float rcount, rnum; - vector ang = '0 0 0'; - entity rune; - - if(self.owner.classname != "player" || time < game_starttime) - { - rune_respawn(); - return; - } - - self.nextthink = time + 0.1; - - // count runes my owner holds - rcount = 0; - rune = find(world, classname, "rune"); - rnum = -1; - while(rune) - { - if(rune.owner == self.owner) - rcount = rcount + 1; - if(rune == self) - rnum = rcount; - rune = find(rune, classname, "rune"); - } - - ang_y = rnum*(360 / rcount) + mod(time, 360)*45;//180; - - makevectors(ang); - - setorigin(self, v_forward*32); -} - -void rune_touch() -{ - if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT) - { - self.think = rune_respawn; - self.nextthink = time; - return; - } - - if(other.classname != "player" || other.health < 1) - return; - if(self.wait > time) - return; // "notouch" time isn't finished - - // detach from the spawn point you're on - rune_unmark_spot(self); - - self.owner = other; - self.enemy.owner = other; - setattachment(self, other, ""); - - other.runes = other.runes | self.runes | self.enemy.runes; - - //self.think = func_null; - //self.nextthink = 0; - self.think = RuneCarriedThink; - self.nextthink = time; - self.touch = func_null; - - self.solid = SOLID_NOT; - setorigin(self, self.origin); - - //sprint(other, strcat("^3You have picked up ", - // RuneName(self.runes & (RUNE_LAST*2-1)), " and ")); - //sprint(other, strcat(RuneName(self.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n")); - - bprint("^3", other.netname, "^7 has picked up ", - RuneName(self.runes & (RUNE_LAST*2-1)), "^7 and "); - bprint(RuneName(self.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n"); -} - -void rune_respawn() -{ - rune_unmark_spot(self); - if(rune_spawn_somewhere(self)) - { - self.solid = SOLID_TRIGGER; - self.touch = rune_touch; - self.think = rune_respawn; - self.nextthink = time + autocvar_g_runematch_shuffletime;//30 + random()*5; // fixme: cvar - } - else - { - // try again later - self.think = rune_respawn; - self.nextthink = time; - } -} - -entity FindRune(entity own, string clname, float r) -{ - entity rune; - float _count, c; - - c = _count = 0; - rune = world; - - do - { - rune = find(rune, classname, clname); - if(!rune) - rune = find(rune, classname, clname); - if(!rune) - break; - if(rune.owner == own) - { - _count = _count + 1; - if(_count >= r) - return rune; - if(r <= 1) - return rune; - } - c = c + 1; - }while(c < 30); - return world; -} - - -void DropRune(entity pl, entity e) -{ - //entity pl; - - //pl = e.owner; - // detach from player - setattachment(e, world, ""); - e.owner = world; - e.enemy.owner = world; - // don't instantly touch player again - e.wait = time + 1; // "notouch" time - e.movetype = MOVETYPE_TOSS; - e.solid = SOLID_TRIGGER; - // reposition itself if not picked up soon - e.think = rune_respawn; - e.nextthink = time + autocvar_g_runematch_respawntime;//15 + random()*5; // fixme: cvar - e.touch = rune_touch; - - pl.runes = pl.runes - (pl.runes & (e.runes | e.enemy.runes)); - - // toss from player - setorigin(e, pl.origin + '0 0 10'); - e.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom(); - - - bprint("^3", pl.netname, "^7 has lost ", - RuneName(e.runes & (RUNE_LAST*2-1)), "^7 and "); - bprint(RuneName(e.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n"); -} - -float RuneMatchesCurse(float r, float c) -{ - float cr; - if(r & RUNE_STRENGTH) - cr = CURSE_WEAK; - else if(r & RUNE_DEFENSE) - cr = CURSE_VULNER; - else if(r & RUNE_REGEN) - cr = CURSE_VENOM; - else if(r & RUNE_SPEED) - cr = CURSE_SLOW; - else if(r & RUNE_VAMPIRE) - cr = CURSE_EMPATHY; - else return FALSE; // fixme: error? - - if(c & cr) - return TRUE; - return FALSE; -} - -// player died, drop runes -// each rune should pair up with a random curse and then be tossed from the player -void DropAllRunes(entity pl) -{ - entity rune, curse; - float rcount, ccount, r, c, rand, prevent_same, numtodrop, tries; - - entity curse1, rune1, curse2, rune2; - - rcount = ccount = r = c = 0; - rune = find(world, classname, "rune"); - while(rune) - { - if(rune.owner == pl) - rcount = rcount + 1; - rune = find(rune, classname, "rune"); - } - curse = find(world, classname, "curse"); - while(curse) - { - if(curse.owner == pl) - ccount = ccount + 1; - curse = find(curse, classname, "curse"); - } - - numtodrop = autocvar_g_runematch_drop_runes_max; - prevent_same = !autocvar_g_runematch_allow_same; - - do - { - rune = find(rune, classname, "rune"); - if(!rune) - break; - if(rune.owner != pl) - continue; - - - // find a random curse - tries = 15; - if(ccount > 1 && prevent_same) - { - // avoid pairing runes and curses that match each other - do{ - rand = floor(random()*ccount) + 1; - curse = FindRune(pl, "curse", rand); - tries = tries - 1; - }while(RuneMatchesCurse(rune.runes, curse.runes) && tries > 0); - if(tries <= 0) - { - bprint("warning: couldn't prevent same rune\n"); - } - } - else - { - rand = floor(random()*ccount) + 1; - curse = FindRune(pl, "curse", rand); - } - - if(!curse) - error("Couldn't fine curse to bind rune to\n"); - - // pair rune and curse - - rune1 = rune; - curse1 = curse; - rune2 = curse1.enemy; - curse2 = rune1.enemy; - - if(rune1 != rune2) // not already attached to each other - { - rune1.enemy = curse1; - curse1.enemy = rune1; - setattachment(curse1, rune1, ""); - rune2.enemy = curse2; - curse2.enemy = rune2; - setattachment(curse2, rune2, ""); - //DropRune(pl, rune2); - //ccount = ccount - 1; - //rcount = rcount - 1; - } - DropRune(pl, rune1); - - if(numtodrop <=0) - { - rune1.think = rune_respawn; - rune1.nextthink = time; - } - - numtodrop = numtodrop - 1; - - ccount = ccount - 1; - rcount = rcount - 1; - - }while(rune); -} - -void rune_reset() -{ - if(self.owner) - if(self.owner.classname != "runematch_spawn_point") - DropAllRunes(self.owner); - rune_respawn(); -} - -void spawn_runes() -{ - float rn, cs, runes_used, curses_used, prevent_same, numrunes; - entity e; - - if(self) - remove(self); - - // fixme: instead of placing them all now, why not - // simply create them all and let them call rune_respawn() as their think? - - runes_used = 0; - curses_used = 0; - - prevent_same = !autocvar_g_runematch_allow_same; - numrunes = RUNE_COUNT; - - while(numrunes > 0) - { - RandomSelection_Init(); - for(rn = RUNE_FIRST; rn <= RUNE_LAST; rn *= 2) - if not(runes_used & rn) - RandomSelection_Add(world, rn, string_null, 1, 1); - rn = RandomSelection_chosen_float; - - RandomSelection_Init(); - for(cs = CURSE_FIRST; cs <= CURSE_LAST; cs *= 2) - if not(curses_used & cs) - if not(prevent_same && cs == RuneMatchesCurse(rn, cs)) - RandomSelection_Add(world, cs, string_null, 1, 1); - cs = RandomSelection_chosen_float; - - if(!rn || !cs) - error("No rune/curse left"); - - runes_used |= rn; - curses_used |= cs; - - e = spawn(); - e.runes = rn; - e.classname = "rune"; - e.touch = rune_touch; - e.think = rune_respawn; - e.nextthink = time; - e.movetype = MOVETYPE_TOSS; - e.solid = SOLID_TRIGGER; - e.flags = FL_ITEM; - e.reset = rune_reset; - setmodel(e, "models/runematch/rune.mdl"); // precision set below - setsize(e, '0 0 -35', '0 0 0'); - - e.enemy = spawn(); - e.enemy.enemy = e; - e.enemy.classname = "curse"; - e.enemy.runes = cs; - //e.enemy.avelocity = '300 500 200'; - setmodel(e.enemy, "models/runematch/curse.mdl"); // precision set below - setorigin(e, '0 0 0'); - setattachment(e.enemy, e, ""); - - e.colormod = RuneColormod(rn); - e.enemy.colormod = RuneColormod(cs); - - e.alpha = e.enemy.alpha = autocvar_g_runematch_rune_alpha;//0.78; - e.effects = e.enemy.effects = autocvar_g_runematch_rune_effects | EF_LOWPRECISION;//EF_ADDITIVE;// | EF_FULLBRIGHT; - - //e.glow_size = e.enemy.glow_size = cvar("g_runematch_rune_glow_size"); - //e.glow_color = e.enemy.glow_color = cvar("g_runematch_rune_glow_color"); - - //rn = RUNE_FIRST; - //cs = CURSE_FIRST; - - numrunes = numrunes - 1; - } -} - -void runematch_init() -{ - if(!g_runematch) - return; - - entity e; - e = spawn(); - e.think = spawn_runes; - e.nextthink = time + 0.1; -} - - -float runematch_point_time; - -// give points to players who are holding runes -void RuneMatchGivePoints() -{ - entity rune; - - if(!g_runematch || !autocvar_g_runematch_pointamt) - return; - - if(gameover) - return; - - if(runematch_point_time > time) - return; - - runematch_point_time = time + autocvar_g_runematch_pointrate; - - rune = world; - do - { - rune = find(rune, classname, "rune"); - if(!rune) - return; - - if(rune.owner.classname == "player") - { - UpdateFrags(rune.owner, autocvar_g_runematch_pointamt); - } - }while(rune); -} - -float RunematchHandleFrags(entity attacker, entity targ, float f) -{ - entity head; - float arunes, trunes, newfrags; - - if(f <= 0) - return f; - if(attacker == targ) - return f; - - arunes = trunes = 0; - - head = find(world, classname, "rune"); - while(head) - { - if(head.owner == attacker) - { - arunes = arunes + 1; - } - else if(head.owner == targ) - { - trunes = trunes + 1; - } - - head = find(head, classname, "rune"); - } - - if(!arunes && !trunes) - return f - 1 + autocvar_g_runematch_frags_norune; // don't give points to players when no runes are involved. - - newfrags = 0; - if(arunes) - { // got a kill while holding runes - newfrags = newfrags + autocvar_g_runematch_frags_killedby_runeholder;//5; - } - if(trunes) - { // killed an enemy holding runes - newfrags = newfrags + autocvar_g_runematch_frags_killed_runeholder;//5; - } - if(newfrags) - f = f - 1 + newfrags; - - return f; -} diff --git a/qcsrc/server/scores.qc b/qcsrc/server/scores.qc index 0df5b69af0..ad10fa5d53 100644 --- a/qcsrc/server/scores.qc +++ b/qcsrc/server/scores.qc @@ -204,13 +204,13 @@ void ScoreInfo_Init(float teams) Net_LinkEntity(scores_initialized, FALSE, 0, ScoreInfo_SendEntity); } if(teams >= 1) - TeamScore_Spawn(COLOR_TEAM1, "Red"); + TeamScore_Spawn(NUM_TEAM_1, "Red"); if(teams >= 2) - TeamScore_Spawn(COLOR_TEAM2, "Blue"); + TeamScore_Spawn(NUM_TEAM_2, "Blue"); if(teams >= 3) - TeamScore_Spawn(COLOR_TEAM3, "Yellow"); + TeamScore_Spawn(NUM_TEAM_3, "Yellow"); if(teams >= 4) - TeamScore_Spawn(COLOR_TEAM4, "Pink"); + TeamScore_Spawn(NUM_TEAM_4, "Pink"); } /* @@ -256,8 +256,8 @@ float PlayerScore_Clear(entity player) 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 @@ -393,15 +393,15 @@ void WinningConditionHelper() // so to match pure, match for :P0: // to match full, match for :S0: + fullstatus = autocvar_g_full_getstatus_responses; + s = GetGametype(); s = strcat(s, ":", autocvar_g_xonoticversion); s = strcat(s, ":P", ftos(cvar_purechanges_count)); s = strcat(s, ":S", ftos(nJoinAllowed(world))); s = strcat(s, ":F", ftos(serverflags)); s = strcat(s, ":M", modname); - s = strcat(s, "::", GetPlayerScoreString(world, 1)); // make this 1 once we can, note: this doesn't contain any : - - fullstatus = autocvar_g_full_getstatus_responses; + s = strcat(s, "::", GetPlayerScoreString(world, (fullstatus ? 1 : 2))); if(teamscores_entities_count) { @@ -527,12 +527,12 @@ void WinningConditionHelper() 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"; @@ -622,7 +622,7 @@ string GetTeamScoreString(float tm, float shortString) if(tm == 0) { // label - for(i = 0; i < MAX_SCORE; ++i) + for(i = 0; i < MAX_TEAMSCORE; ++i) if(teamscores_flags[i] & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_PRIMARY) { f = teamscores_flags[i]; @@ -630,7 +630,7 @@ string GetTeamScoreString(float tm, float shortString) out = strcat(out, GetScoreLogLabel(l, f), ","); } if(shortString < 2) - for(i = 0; i < MAX_SCORE; ++i) + for(i = 0; i < MAX_TEAMSCORE; ++i) if(teamscores_flags[i] & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_SECONDARY) { f = teamscores_flags[i]; @@ -638,7 +638,7 @@ string GetTeamScoreString(float tm, float shortString) out = strcat(out, GetScoreLogLabel(l, f), ","); } if(shortString < 1) - for(i = 0; i < MAX_SCORE; ++i) + for(i = 0; i < MAX_TEAMSCORE; ++i) if(teamscores_flags[i] & SFL_SORT_PRIO_MASK != SFL_SORT_PRIO_PRIMARY) if(teamscores_flags[i] & SFL_SORT_PRIO_MASK != SFL_SORT_PRIO_SECONDARY) { @@ -795,7 +795,7 @@ void Score_NicePrint_Team(entity to, float t, float w) sk = teamscorekeepers[t - 1]; if(sk) { - s = strcat(s, ColoredTeamName(t)); + s = strcat(s, Team_ColoredFullName(t)); for(i = 0; i < MAX_TEAMSCORE; ++i) if(teamscores_label[i] != "") { diff --git a/qcsrc/server/scores_rules.qc b/qcsrc/server/scores_rules.qc index 13fd49f29b..d60f4563c1 100644 --- a/qcsrc/server/scores_rules.qc +++ b/qcsrc/server/scores_rules.qc @@ -44,17 +44,6 @@ void ScoreRules_generic() 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 @@ -104,17 +93,6 @@ void ScoreRules_race() 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 diff --git a/qcsrc/server/sv_main.qc b/qcsrc/server/sv_main.qc index c91c1ac189..8d81e03806 100644 --- a/qcsrc/server/sv_main.qc +++ b/qcsrc/server/sv_main.qc @@ -153,7 +153,6 @@ Called before each frame by the server float game_delay; float game_delay_last; -void RuneMatchGivePoints(); float RedirectionThink(); entity SelectSpawnPoint (float anypoint); void StartFrame (void) @@ -210,19 +209,13 @@ void StartFrame (void) 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; @@ -238,7 +231,6 @@ void StartFrame (void) CreatureFrame (); CheckRules_World (); - RuneMatchGivePoints(); bot_serverframe(); FOR_EACH_PLAYER(self) diff --git a/qcsrc/server/t_items.qc b/qcsrc/server/t_items.qc index bf70da0286..40abd18b13 100644 --- a/qcsrc/server/t_items.qc +++ b/qcsrc/server/t_items.qc @@ -282,8 +282,6 @@ float have_pickup_item(void) return TRUE; if(autocvar_g_powerups == 0) return FALSE; - if(g_lms) - return FALSE; if(g_ca) return FALSE; if(g_arena) @@ -295,8 +293,6 @@ float have_pickup_item(void) return TRUE; if(autocvar_g_pickup_items == 0) return FALSE; - if(g_lms) - return FALSE; if(g_ca) return FALSE; if(g_weaponarena) @@ -630,16 +626,16 @@ float Item_GiveTo(entity item, entity player) 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) // AnnounceTo(player, "ammo"); if (WEPSET_CONTAINS_EW(item, WEP_MINSTANEX)) - W_GiveWeapon (player, WEP_MINSTANEX, item.netname); + W_GiveWeapon (player, WEP_MINSTANEX); player.health = 100; } @@ -657,7 +653,7 @@ float Item_GiveTo(entity item, entity player) // 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 @@ -709,7 +705,7 @@ float Item_GiveTo(entity item, entity player) pickedup = TRUE; for(i = WEP_FIRST; i <= WEP_LAST; ++i) if(WEPSET_CONTAINS_AW(it, i)) - W_GiveWeapon (player, i, item.netname); + W_GiveWeapon(player, i); } } diff --git a/qcsrc/server/t_jumppads.qc b/qcsrc/server/t_jumppads.qc index 5a5042b3d4..0b6f7fc4cd 100644 --- a/qcsrc/server/t_jumppads.qc +++ b/qcsrc/server/t_jumppads.qc @@ -37,6 +37,8 @@ vector trigger_push_calculatevelocity(vector org, entity tgt, float ht) torg = tgt.origin + (tgt.mins + tgt.maxs) * 0.5; grav = autocvar_sv_gravity; + if(other.gravity) + grav *= other.gravity; zdist = torg_z - org_z; sdist = vlen(torg - org - zdist * '0 0 1'); diff --git a/qcsrc/server/teamplay.qc b/qcsrc/server/teamplay.qc index 1ed2f533b3..16236dd16b 100644 --- a/qcsrc/server/teamplay.qc +++ b/qcsrc/server/teamplay.qc @@ -13,46 +13,6 @@ void TeamchangeFrags(entity e) PlayerScore_Clear(e); } -vector TeamColor(float teem) -{ - switch(teem) - { - case COLOR_TEAM1: - return '1 0.0625 0.0625'; - case COLOR_TEAM2: - return '0.0625 0.0625 1'; - case COLOR_TEAM3: - return '1 1 0.0625'; - case COLOR_TEAM4: - return '1 0.0625 1'; - default: - return '1 1 1'; - } -} - -string TeamName(float t) -{ - return strcat(Team_ColorName(t), " Team"); -} -string ColoredTeamName(float t) -{ - return strcat(Team_ColorCode(t), Team_ColorName(t), " Team^7"); -} -string TeamNoName(float t) -{ - // fixme: Search for team entities and get their .netname's! - if(t == 1) - return "Red Team"; - if(t == 2) - return "Blue Team"; - if(t == 3) - return "Yellow Team"; - if(t == 4) - return "Pink Team"; - return "Neutral Team"; -} - -void runematch_init(); void tdm_init(); void entcs_init(); @@ -146,33 +106,20 @@ void InitGameplayMode() have_team_spawns = -1; // request team spawns } - if(g_runematch) - { - // ActivateTeamplay(); - fraglimit_override = autocvar_g_runematch_point_limit; - leadlimit_override = autocvar_g_runematch_point_leadlimit; - runematch_init(); - } - if(g_lms) { fraglimit_override = autocvar_g_lms_lives_override; 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) @@ -180,9 +127,9 @@ void InitGameplayMode() 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(); @@ -202,7 +149,7 @@ void InitGameplayMode() if(g_assault) { ActivateTeamplay(); - ScoreRules_assault(); + MUTATOR_ADD(gamemode_assault); have_team_spawns = -1; // request team spawns } @@ -416,13 +363,13 @@ void SetPlayerTeam(entity pl, float t, float s, float noprint) float _color; if(t == 4) - _color = COLOR_TEAM4 - 1; + _color = NUM_TEAM_4 - 1; else if(t == 3) - _color = COLOR_TEAM3 - 1; + _color = NUM_TEAM_3 - 1; else if(t == 2) - _color = COLOR_TEAM2 - 1; + _color = NUM_TEAM_2 - 1; else - _color = COLOR_TEAM1 - 1; + _color = NUM_TEAM_1 - 1; SetPlayerColors(pl,_color); @@ -430,7 +377,7 @@ void SetPlayerTeam(entity pl, float t, float s, float noprint) LogTeamchange(pl.playerid, pl.team, 3); // log manual team join if(!noprint) - bprint(pl.netname, "^7 has changed from ", TeamNoName(s), " to ", TeamNoName(t), "\n"); + bprint(pl.netname, "^7 has changed from ", Team_NumberToColoredFullName(s), "^7 to ", Team_NumberToColoredFullName(t), "\n"); } } @@ -452,10 +399,10 @@ void CheckAllowedTeams (entity for_whom) head = findchain(classname, "onslaught_generator"); while (head) { - if (head.team == COLOR_TEAM1) c1 = 0; - if (head.team == COLOR_TEAM2) c2 = 0; - if (head.team == COLOR_TEAM3) c3 = 0; - if (head.team == COLOR_TEAM4) c4 = 0; + if (head.team == NUM_TEAM_1) c1 = 0; + if (head.team == NUM_TEAM_2) c2 = 0; + if (head.team == NUM_TEAM_3) c3 = 0; + if (head.team == NUM_TEAM_4) c4 = 0; head = head.chain; } } @@ -497,13 +444,13 @@ void CheckAllowedTeams (entity for_whom) { if(!(g_domination && head.netname == "")) { - if(head.team == COLOR_TEAM1) + if(head.team == NUM_TEAM_1) c1 = 0; - else if(head.team == COLOR_TEAM2) + else if(head.team == NUM_TEAM_2) c2 = 0; - else if(head.team == COLOR_TEAM3) + else if(head.team == NUM_TEAM_3) c3 = 0; - else if(head.team == COLOR_TEAM4) + else if(head.team == NUM_TEAM_4) c4 = 0; } head = find(head, classname, teament_name); @@ -533,13 +480,13 @@ void CheckAllowedTeams (entity for_whom) } // if player has a forced team, ONLY allow that one - if(self.team_forced == COLOR_TEAM1 && c1 >= 0) + if(self.team_forced == NUM_TEAM_1 && c1 >= 0) c2 = c3 = c4 = -1; - else if(self.team_forced == COLOR_TEAM2 && c2 >= 0) + else if(self.team_forced == NUM_TEAM_2 && c2 >= 0) c1 = c3 = c4 = -1; - else if(self.team_forced == COLOR_TEAM3 && c3 >= 0) + else if(self.team_forced == NUM_TEAM_3 && c3 >= 0) c1 = c2 = c4 = -1; - else if(self.team_forced == COLOR_TEAM4 && c4 >= 0) + else if(self.team_forced == NUM_TEAM_4 && c4 >= 0) c1 = c2 = c3 = -1; } @@ -576,7 +523,7 @@ void GetTeamCounts(entity ignore) bvalue = value; else bvalue = 0; - if(t == COLOR_TEAM1) + if(t == NUM_TEAM_1) { if(c1 >= 0) { @@ -584,7 +531,7 @@ void GetTeamCounts(entity ignore) cb1 = cb1 + bvalue; } } - if(t == COLOR_TEAM2) + if(t == NUM_TEAM_2) { if(c2 >= 0) { @@ -592,7 +539,7 @@ void GetTeamCounts(entity ignore) cb2 = cb2 + bvalue; } } - if(t == COLOR_TEAM3) + if(t == NUM_TEAM_3) { if(c3 >= 0) { @@ -600,7 +547,7 @@ void GetTeamCounts(entity ignore) cb3 = cb3 + bvalue; } } - if(t == COLOR_TEAM4) + if(t == NUM_TEAM_4) { if(c4 >= 0) { @@ -769,13 +716,13 @@ float JoinBestTeam(entity pl, float only_return_best, float forcebestteam) // if he's not on a valid team, then let other code put him on the smallest team if(!forcebestteam) { - if( c1 >= 0 && pl.team == COLOR_TEAM1) + if( c1 >= 0 && pl.team == NUM_TEAM_1) selectedteam = pl.team; - else if(c2 >= 0 && pl.team == COLOR_TEAM2) + else if(c2 >= 0 && pl.team == NUM_TEAM_2) selectedteam = pl.team; - else if(c3 >= 0 && pl.team == COLOR_TEAM3) + else if(c3 >= 0 && pl.team == NUM_TEAM_3) selectedteam = pl.team; - else if(c4 >= 0 && pl.team == COLOR_TEAM4) + else if(c4 >= 0 && pl.team == NUM_TEAM_4) selectedteam = pl.team; else selectedteam = -1; @@ -802,19 +749,19 @@ float JoinBestTeam(entity pl, float only_return_best, float forcebestteam) TeamchangeFrags(self); if(smallest == 1) { - SetPlayerColors(pl, COLOR_TEAM1 - 1); + SetPlayerColors(pl, NUM_TEAM_1 - 1); } else if(smallest == 2) { - SetPlayerColors(pl, COLOR_TEAM2 - 1); + SetPlayerColors(pl, NUM_TEAM_2 - 1); } else if(smallest == 3) { - SetPlayerColors(pl, COLOR_TEAM3 - 1); + SetPlayerColors(pl, NUM_TEAM_3 - 1); } else if(smallest == 4) { - SetPlayerColors(pl, COLOR_TEAM4 - 1); + SetPlayerColors(pl, NUM_TEAM_4 - 1); } else { @@ -844,21 +791,21 @@ void SV_ChangeTeam(float _color) scolor = self.clientcolors & 0x0F; dcolor = _color & 0x0F; - if(scolor == COLOR_TEAM1 - 1) + if(scolor == NUM_TEAM_1 - 1) steam = 1; - else if(scolor == COLOR_TEAM2 - 1) + else if(scolor == NUM_TEAM_2 - 1) steam = 2; - else if(scolor == COLOR_TEAM3 - 1) + else if(scolor == NUM_TEAM_3 - 1) steam = 3; - else // if(scolor == COLOR_TEAM4 - 1) + else // if(scolor == NUM_TEAM_4 - 1) steam = 4; - if(dcolor == COLOR_TEAM1 - 1) + if(dcolor == NUM_TEAM_1 - 1) dteam = 1; - else if(dcolor == COLOR_TEAM2 - 1) + else if(dcolor == NUM_TEAM_2 - 1) dteam = 2; - else if(dcolor == COLOR_TEAM3 - 1) + else if(dcolor == NUM_TEAM_3 - 1) dteam = 3; - else // if(dcolor == COLOR_TEAM4 - 1) + else // if(dcolor == NUM_TEAM_4 - 1) dteam = 4; CheckAllowedTeams(self); @@ -947,13 +894,13 @@ void ShufflePlayerOutOfTeam (float source_team) } if(source_team == 1) - steam = COLOR_TEAM1; + steam = NUM_TEAM_1; else if(source_team == 2) - steam = COLOR_TEAM2; + steam = NUM_TEAM_2; else if(source_team == 3) - steam = COLOR_TEAM3; + steam = NUM_TEAM_3; else // if(source_team == 4) - steam = COLOR_TEAM4; + steam = NUM_TEAM_4; lowest_bot = world; lowest_bot_score = 999999999; @@ -1048,7 +995,7 @@ void ShufflePlayerOutOfTeam (float source_team) if(selected.deadflag == DEAD_NO) Damage(selected, selected, selected, 100000, DEATH_AUTOTEAMCHANGE, selected.origin, '0 0 0'); - centerprint(selected, strcat("You have been moved into a different team to improve team balance\nYou are now on: ", ColoredTeamName(selected.team))); + centerprint(selected, strcat("You have been moved into a different team to improve team balance\nYou are now on: ", Team_ColoredFullName(selected.team))); } // code from here on is just to support maps that don't have team entities @@ -1072,12 +1019,12 @@ void tdm_spawnteams() numteams = autocvar_g_tdm_teams; numteams = bound(2, numteams, 4); - tdm_spawnteam("Red", COLOR_TEAM1-1); - tdm_spawnteam("Blue", COLOR_TEAM2-1); + tdm_spawnteam("Red", NUM_TEAM_1-1); + tdm_spawnteam("Blue", NUM_TEAM_2-1); if(numteams >= 3) - tdm_spawnteam("Yellow", COLOR_TEAM3-1); + tdm_spawnteam("Yellow", NUM_TEAM_3-1); if(numteams >= 4) - tdm_spawnteam("Pink", COLOR_TEAM4-1); + tdm_spawnteam("Pink", NUM_TEAM_4-1); } void tdm_delayedinit() diff --git a/qcsrc/server/tturrets/system/system_main.qc b/qcsrc/server/tturrets/system/system_main.qc index dd58b3cee2..726aa7be44 100644 --- a/qcsrc/server/tturrets/system/system_main.qc +++ b/qcsrc/server/tturrets/system/system_main.qc @@ -1060,12 +1060,7 @@ float turret_stdproc_init (string cvar_base_name, string base, string head, floa 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) { diff --git a/qcsrc/server/tturrets/units/unit_machinegun.qc b/qcsrc/server/tturrets/units/unit_machinegun.qc index 9358cd7baf..8f18d845a9 100644 --- a/qcsrc/server/tturrets/units/unit_machinegun.qc +++ b/qcsrc/server/tturrets/units/unit_machinegun.qc @@ -31,6 +31,7 @@ void turret_machinegun_std_init() } 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; diff --git a/qcsrc/server/tturrets/units/unit_phaser.qc b/qcsrc/server/tturrets/units/unit_phaser.qc index 91794929b6..2f28c7c3b3 100644 --- a/qcsrc/server/tturrets/units/unit_phaser.qc +++ b/qcsrc/server/tturrets/units/unit_phaser.qc @@ -60,7 +60,6 @@ void beam_think() entity oldself; oldself = self; self = self.owner; - //w_deathtypestring = "was phased out of existence"; FireImoBeam ( self.tur_shotorg, self.tur_shotorg + self.tur_shotdir_updated * self.target_range, '-1 -1 -1' * self.shot_radius, diff --git a/qcsrc/server/tturrets/units/unit_plasma.qc b/qcsrc/server/tturrets/units/unit_plasma.qc index aacca522ec..f4a60e545a 100644 --- a/qcsrc/server/tturrets/units/unit_plasma.qc +++ b/qcsrc/server/tturrets/units/unit_plasma.qc @@ -25,6 +25,44 @@ void turret_plasma_dual_postthink() self.tur_head.frame = 0; } +void turret_plasma_minsta_attack (void) +{ + float flying; + flying = IsFlying(self); // do this BEFORE to make the trace values from FireRailgunBullet last + + FireRailgunBullet (self.tur_shotorg, self.tur_shotorg + self.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000, + 800, 0, 0, 0, 0, DEATH_TURRET_PLASMA); + + + pointparticles(particleeffectnum("nex_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); + + // teamcolor / hit beam effect + vector v; + v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos); + if(teamplay) + { + switch(self.team) + { + case NUM_TEAM_1: // Red + WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3RED"), self.tur_shotorg, v); + break; + case NUM_TEAM_2: // Blue + WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3BLUE"), self.tur_shotorg, v); + break; + case NUM_TEAM_3: // Yellow + WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3YELLOW"), self.tur_shotorg, v); + break; + case NUM_TEAM_4: // Pink + WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3PINK"), self.tur_shotorg, v); + break; + } + } + else + WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3"), self.tur_shotorg, v); + if (self.tur_head.frame == 0) + self.tur_head.frame = 1; +} + void turret_plasma_attack() { entity missile = turret_projectile("weapons/hagar_fire.wav", 1, 0, DEATH_TURRET_PLASMA, PROJECTILE_ELECTRO_BEAM, TRUE, TRUE); @@ -64,7 +102,10 @@ void turret_plasma_std_init() self.firecheck_flags |= TFL_FIRECHECK_AFF; // Our fireing routine - self.turret_firefunc = turret_plasma_attack; + if(g_minstagib) + self.turret_firefunc = turret_plasma_minsta_attack; + else + self.turret_firefunc = turret_plasma_attack; // Custom per turret frame stuff. usualy animation. self.turret_postthink = turret_plasma_postthink; diff --git a/qcsrc/server/tturrets/units/unit_tessla.qc b/qcsrc/server/tturrets/units/unit_tessla.qc index 87fda8ed27..5969938912 100644 --- a/qcsrc/server/tturrets/units/unit_tessla.qc +++ b/qcsrc/server/tturrets/units/unit_tessla.qc @@ -86,8 +86,6 @@ void turret_tesla_fire() entity e, t; float d, r, i; - //w_deathtypestring = "discoverd how a tesla coil works"; - d = self.shot_dmg; r = self.target_range; e = spawn(); diff --git a/qcsrc/server/tturrets/units/unit_walker.qc b/qcsrc/server/tturrets/units/unit_walker.qc index 4bd1d0760b..20100de047 100644 --- a/qcsrc/server/tturrets/units/unit_walker.qc +++ b/qcsrc/server/tturrets/units/unit_walker.qc @@ -38,7 +38,7 @@ void walker_meele_do_dmg() { if (turret_validate_target(self, e, self.target_validate_flags)) if (e != self && e.owner != self) - Damage(e, self, self, autocvar_g_turrets_unit_walker_std_meele_dmg, DEATH_TURRET_WALKER_MEELE, '0 0 0', v_forward * autocvar_g_turrets_unit_walker_std_meele_force); + Damage(e, self, self, autocvar_g_turrets_unit_walker_std_meele_dmg, DEATH_TURRET_WALK_MEELE, '0 0 0', v_forward * autocvar_g_turrets_unit_walker_std_meele_force); e = e.chain; } @@ -51,7 +51,7 @@ void walker_setnoanim() } void walker_rocket_explode() { - RadiusDamage (self, self.owner, autocvar_g_turrets_unit_walker_std_rocket_dmg, 0, autocvar_g_turrets_unit_walker_std_rocket_radius, self, autocvar_g_turrets_unit_walker_std_rocket_force, DEATH_TURRET_WALKER_ROCKET, world); + RadiusDamage (self, self.owner, autocvar_g_turrets_unit_walker_std_rocket_dmg, 0, autocvar_g_turrets_unit_walker_std_rocket_radius, self, autocvar_g_turrets_unit_walker_std_rocket_force, DEATH_TURRET_WALK_ROCKET, world); remove (self); } @@ -515,7 +515,7 @@ void walker_postthink() void walker_attack() { sound (self, CH_WEAPON_A, "weapons/uzi_fire.wav", VOL_BASE, ATTN_NORM); - fireBallisticBullet (self.tur_shotorg, self.tur_shotdir_updated, self.shot_spread, self.shot_speed, 5, self.shot_dmg, self.shot_force, DEATH_TURRET_WALKER_GUN, 0, 1, autocvar_g_balance_uzi_bulletconstant); + fireBallisticBullet (self.tur_shotorg, self.tur_shotdir_updated, self.shot_spread, self.shot_speed, 5, self.shot_dmg, self.shot_force, DEATH_TURRET_WALK_GUN, 0, 1, autocvar_g_balance_uzi_bulletconstant); endFireBallisticBullet(); pointparticles(particleeffectnum("laser_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); } diff --git a/qcsrc/server/vehicles/bumblebee.qc b/qcsrc/server/vehicles/bumblebee.qc index b9c7dbfb83..429b8e5f9f 100644 --- a/qcsrc/server/vehicles/bumblebee.qc +++ b/qcsrc/server/vehicles/bumblebee.qc @@ -86,7 +86,7 @@ void bumb_fire_cannon(entity _gun, string _tagname, entity _owner) vehicles_projectile("bigplasma_muzzleflash", "weapons/flacexp3.wav", v, normalize(v_forward + randomvec() * autocvar_g_vehicle_bumblebee_cannon_spread) * autocvar_g_vehicle_bumblebee_cannon_speed, autocvar_g_vehicle_bumblebee_cannon_damage, autocvar_g_vehicle_bumblebee_cannon_radius, autocvar_g_vehicle_bumblebee_cannon_force, 0, - DEATH_BUMB_GUN, PROJECTILE_BUMBLE_GUN, 0, TRUE, TRUE, _owner); + DEATH_VH_BUMB_GUN, PROJECTILE_BUMBLE_GUN, 0, TRUE, TRUE, _owner); } float bumb_gunner_frame() @@ -735,7 +735,7 @@ void bumb_blowup() autocvar_g_vehicle_bumblebee_blowup_edgedamage, autocvar_g_vehicle_bumblebee_blowup_radius, self, autocvar_g_vehicle_bumblebee_blowup_forceintensity, - DEATH_WAKIBLOWUP, world); + DEATH_VH_BUMB_DEATH, world); sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM); pointparticles(particleeffectnum("explosion_large"), randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1); diff --git a/qcsrc/server/vehicles/racer.qc b/qcsrc/server/vehicles/racer.qc index 93b27df975..f5788c60b4 100644 --- a/qcsrc/server/vehicles/racer.qc +++ b/qcsrc/server/vehicles/racer.qc @@ -129,7 +129,7 @@ void racer_fire_cannon(string tagname) bolt = vehicles_projectile("wakizashi_gun_muzzleflash", "weapons/lasergun_fire.wav", v, normalize(v_forward + randomvec() * autocvar_g_vehicle_racer_cannon_spread) * autocvar_g_vehicle_racer_cannon_speed, autocvar_g_vehicle_racer_cannon_damage, autocvar_g_vehicle_racer_cannon_radius, autocvar_g_vehicle_racer_cannon_force, 0, - DEATH_WAKIGUN, PROJECTILE_WAKICANNON, 0, TRUE, TRUE, self.owner); + DEATH_VH_WAKI_GUN, PROJECTILE_WAKICANNON, 0, TRUE, TRUE, self.owner); // Fix z-aim (for chase mode) v = normalize(trace_endpos - bolt.origin); @@ -243,7 +243,7 @@ void racer_fire_rocket(string tagname, entity trg) entity rocket = rocket = vehicles_projectile("wakizashi_rocket_launch", "weapons/rocket_fire.wav", v, v_forward * autocvar_g_vehicle_racer_rocket_speed, autocvar_g_vehicle_racer_rocket_damage, autocvar_g_vehicle_racer_rocket_radius, autocvar_g_vehicle_racer_rocket_force, 3, - DEATH_WAKIROCKET, PROJECTILE_WAKIROCKET, 20, FALSE, FALSE, self.owner); + DEATH_VH_WAKI_ROCKET, PROJECTILE_WAKIROCKET, 20, FALSE, FALSE, self.owner); rocket.lip = autocvar_g_vehicle_racer_rocket_accel * sys_frametime; rocket.wait = autocvar_g_vehicle_racer_rocket_turnrate; @@ -542,7 +542,7 @@ void racer_blowup() autocvar_g_vehicle_racer_blowup_edgedamage, autocvar_g_vehicle_racer_blowup_radius, world, autocvar_g_vehicle_racer_blowup_forceintensity, - DEATH_WAKIBLOWUP, world); + DEATH_VH_WAKI_DEATH, world); self.nextthink = time + autocvar_g_vehicle_racer_respawntime; self.think = racer_spawn_default; diff --git a/qcsrc/server/vehicles/raptor.qc b/qcsrc/server/vehicles/raptor.qc index 11b9081a60..e899d4a314 100644 --- a/qcsrc/server/vehicles/raptor.qc +++ b/qcsrc/server/vehicles/raptor.qc @@ -93,7 +93,7 @@ void raptor_bomblet_boom() RadiusDamage (self, self.realowner, autocvar_g_vehicle_raptor_bomblet_damage, autocvar_g_vehicle_raptor_bomblet_edgedamage, autocvar_g_vehicle_raptor_bomblet_radius, world, - autocvar_g_vehicle_raptor_bomblet_force, DEATH_RAPTOR_BOMB, world); + autocvar_g_vehicle_raptor_bomblet_force, DEATH_VH_RAPT_BOMB, world); remove(self); } @@ -124,7 +124,7 @@ void raptor_bomb_burst() entity bomblet; float i; - Damage_DamageInfo(self.origin, 0, 0, 0, '0 0 0', DEATH_RAPTOR_BOMB_SPLIT, 0, self); + Damage_DamageInfo(self.origin, 0, 0, 0, '0 0 0', DEATH_VH_RAPT_FRAGMENT, 0, self); for(i = 0; i < autocvar_g_vehicle_raptor_bomblets; ++i) { @@ -185,7 +185,7 @@ void raptor_fire_cannon(entity gun, string tagname) vehicles_projectile("raptor_cannon_muzzleflash", "weapons/lasergun_fire.wav", gettaginfo(gun, gettagindex(gun, tagname)), normalize(v_forward + randomvec() * autocvar_g_vehicle_raptor_cannon_spread) * autocvar_g_vehicle_raptor_cannon_speed, autocvar_g_vehicle_raptor_cannon_damage, autocvar_g_vehicle_raptor_cannon_radius, autocvar_g_vehicle_raptor_cannon_force, 0, - DEATH_RAPTOR_CANNON, PROJECTILE_RAPTORCANNON, 0, TRUE, TRUE, self.owner); + DEATH_VH_RAPT_CANNON, PROJECTILE_RAPTORCANNON, 0, TRUE, TRUE, self.owner); } void raptor_think() @@ -690,7 +690,7 @@ void raptor_blowup() { self.deadflag = DEAD_DEAD; self.vehicle_exit(VHEF_NORMAL); - RadiusDamage (self, self.enemy, 250, 15, 250, world, 250, DEATH_WAKIBLOWUP, world); + RadiusDamage (self, self.enemy, 250, 15, 250, world, 250, DEATH_VH_RAPT_DEATH, world); self.alpha = -1; self.movetype = MOVETYPE_NONE; diff --git a/qcsrc/server/vehicles/spiderbot.qc b/qcsrc/server/vehicles/spiderbot.qc index de12407f55..a66b564773 100644 --- a/qcsrc/server/vehicles/spiderbot.qc +++ b/qcsrc/server/vehicles/spiderbot.qc @@ -257,7 +257,7 @@ void spiderbot_rocket_do() rocket = vehicles_projectile("spiderbot_rocket_launch", "weapons/rocket_fire.wav", v, normalize(randomvec() * autocvar_g_vehicle_spiderbot_rocket_spread + v_forward) * autocvar_g_vehicle_spiderbot_rocket_speed, autocvar_g_vehicle_spiderbot_rocket_damage, autocvar_g_vehicle_spiderbot_rocket_radius, autocvar_g_vehicle_spiderbot_rocket_force, 1, - DEATH_SBROCKET, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, FALSE, TRUE, self.owner); + DEATH_VH_SPID_ROCKET, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, FALSE, TRUE, self.owner); crosshair_trace(self.owner); float _dist = (random() * autocvar_g_vehicle_spiderbot_rocket_radius) + vlen(v - trace_endpos); _dist -= (random() * autocvar_g_vehicle_spiderbot_rocket_radius) ; @@ -271,7 +271,7 @@ void spiderbot_rocket_do() rocket = vehicles_projectile("spiderbot_rocket_launch", "weapons/rocket_fire.wav", v, normalize(v_forward) * autocvar_g_vehicle_spiderbot_rocket_speed, autocvar_g_vehicle_spiderbot_rocket_damage, autocvar_g_vehicle_spiderbot_rocket_radius, autocvar_g_vehicle_spiderbot_rocket_force, 1, - DEATH_SBROCKET, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, FALSE, FALSE, self.owner); + DEATH_VH_SPID_ROCKET, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, FALSE, FALSE, self.owner); crosshair_trace(self.owner); rocket.pos1 = trace_endpos; rocket.nextthink = time; @@ -283,7 +283,7 @@ void spiderbot_rocket_do() rocket = vehicles_projectile("spiderbot_rocket_launch", "weapons/rocket_fire.wav", v, normalize(v_forward) * autocvar_g_vehicle_spiderbot_rocket_speed, autocvar_g_vehicle_spiderbot_rocket_damage, autocvar_g_vehicle_spiderbot_rocket_radius, autocvar_g_vehicle_spiderbot_rocket_force, 1, - DEATH_SBROCKET, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, FALSE, TRUE, self.owner); + DEATH_VH_SPID_ROCKET, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, FALSE, TRUE, self.owner); crosshair_trace(self.owner); @@ -498,11 +498,12 @@ float spiderbot_frame() //void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, float lifetime, float damage, float force, float dtype, float tracereffects, float gravityfactor, float bulletconstant) fireBallisticBullet(v, v_forward, autocvar_g_vehicle_spiderbot_minigun_spread, autocvar_g_vehicle_spiderbot_minigun_speed, - 5, autocvar_g_vehicle_spiderbot_minigun_damage, autocvar_g_vehicle_spiderbot_minigun_force, DEATH_SBMINIGUN, 0, 1, autocvar_g_vehicle_spiderbot_minigun_bulletconstant); + 5, autocvar_g_vehicle_spiderbot_minigun_damage, autocvar_g_vehicle_spiderbot_minigun_force, DEATH_VH_SPID_MINIGUN, 0, 1, autocvar_g_vehicle_spiderbot_minigun_bulletconstant); + endFireBallisticBullet(); // fireBullet (v, v_forward, autocvar_g_vehicle_spiderbot_minigun_spread, autocvar_g_vehicle_spiderbot_minigun_damage, -// autocvar_g_vehicle_spiderbot_minigun_spread, DEATH_SBMINIGUN, 0); +// autocvar_g_vehicle_spiderbot_minigun_spread, DEATH_VH_SPID_MINIGUN, 0); sound (gun, CH_WEAPON_A, "weapons/uzi_fire.wav", VOL_BASE, ATTN_NORM); //trailparticles(self, particleeffectnum("spiderbot_minigun_trail"), v, trace_endpos); @@ -722,7 +723,7 @@ void spiderbot_blowup() SUB_SetFade(g1, time, min(autocvar_g_vehicle_spiderbot_respawntime, 10)); SUB_SetFade(g2, time, min(autocvar_g_vehicle_spiderbot_respawntime, 10)); - RadiusDamage (self, self.enemy, 250, 15, 250, world, 250, DEATH_SBBLOWUP, world); + RadiusDamage (self, self.enemy, 250, 15, 250, world, 250, DEATH_VH_SPID_DEATH, world); self.alpha = self.tur_head.alpha = self.gun1.alpha = self.gun2.alpha = -1; self.movetype = MOVETYPE_NONE; diff --git a/qcsrc/server/vehicles/vehicles.qc b/qcsrc/server/vehicles/vehicles.qc index 5e377079e0..1b1ae3f647 100644 --- a/qcsrc/server/vehicles/vehicles.qc +++ b/qcsrc/server/vehicles/vehicles.qc @@ -544,7 +544,7 @@ void vehicles_touch() if(vehicles_crushable(other)) { if(vlen(self.velocity) != 0) - Damage(other, self, self.owner, autocvar_g_vehicles_crush_dmg, DEATH_VHCRUSH, '0 0 0', normalize(other.origin - self.origin) * autocvar_g_vehicles_crush_force); + Damage(other, self, self.owner, autocvar_g_vehicles_crush_dmg, DEATH_VH_CRUSH, '0 0 0', normalize(other.origin - self.origin) * autocvar_g_vehicles_crush_force); return; // Dont do selfdamage when hitting "soft targets". } @@ -1033,7 +1033,7 @@ void vehicles_showwp() } if(teamplay && self.team) - rgb = TeamColor(self.team); + rgb = Team_ColorRGB(self.team); else rgb = '1 1 1'; WaypointSprite_Spawn("vehicle", 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, TRUE, RADARICON_POWERUP, rgb); @@ -1268,14 +1268,14 @@ float vehicle_initialize(string net_name, 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); @@ -1315,6 +1315,9 @@ float vehicle_initialize(string net_name, self.pos1 = self.origin; self.pos2 = self.angles; self.tur_head.team = self.team; + + if(MUTATOR_CALLHOOK(VehicleSpawn)) + return FALSE; return TRUE; } diff --git a/qcsrc/server/w_common.qc b/qcsrc/server/w_common.qc index 67f5b3356b..2e0c1e8f02 100644 --- a/qcsrc/server/w_common.qc +++ b/qcsrc/server/w_common.qc @@ -1,5 +1,5 @@ -void W_GiveWeapon (entity e, float wep, string name) +void W_GiveWeapon (entity e, float wep) { entity oldself; @@ -12,12 +12,8 @@ void W_GiveWeapon (entity e, float wep, string name) self = e; if not(g_minstagib) - if (other.classname == "player") - { - sprint (other, "You got the ^2"); - sprint (other, name); - sprint (other, "\n"); - } + if(other.classname == "player") + { Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_WEAPON_GOT, wep); } self = oldself; } @@ -170,6 +166,7 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f .float dmg_force; .float dmg_radius; .float dmg_total; +//.float last_yoda; void W_BallisticBullet_Hit (void) { float f, q, g; @@ -190,8 +187,11 @@ void W_BallisticBullet_Hit (void) 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) diff --git a/qcsrc/server/w_crylink.qc b/qcsrc/server/w_crylink.qc index 1bb9ad6004..b2472df2ae 100644 --- a/qcsrc/server/w_crylink.qc +++ b/qcsrc/server/w_crylink.qc @@ -684,6 +684,14 @@ float w_crylink(float req) { W_Reload(min(autocvar_g_balance_crylink_primary_ammo, autocvar_g_balance_crylink_secondary_ammo), autocvar_g_balance_crylink_reload_ammo, autocvar_g_balance_crylink_reload_time, "weapons/reload.wav"); } + else if (req == WR_SUICIDEMESSAGE) + { + return WEAPON_CRYLINK_SUICIDE; + } + else if (req == WR_KILLMESSAGE) + { + return WEAPON_CRYLINK_MURDER; + } return TRUE; } #endif @@ -712,19 +720,6 @@ float w_crylink(float req) precache_sound("weapons/crylink_impact2.wav"); precache_sound("weapons/crylink_impact.wav"); } - else if (req == WR_SUICIDEMESSAGE) - { - w_deathtypestring = _("%s succeeded at self-destructing themself with the Crylink"); - } - else if (req == WR_KILLMESSAGE) - { - if(w_deathtype & HITTYPE_BOUNCE) - w_deathtypestring = _("%s could not hide from %s's Crylink"); // unchecked: SPLASH (SECONDARY can't be) - else if(w_deathtype & HITTYPE_SPLASH) - w_deathtypestring = _("%s was too close to %s's Crylink"); // unchecked: SECONDARY - else - w_deathtypestring = _("%s took a close look at %s's Crylink"); // unchecked: SECONDARY - } return TRUE; } #endif diff --git a/qcsrc/server/w_electro.qc b/qcsrc/server/w_electro.qc index 082e454ace..972642343b 100644 --- a/qcsrc/server/w_electro.qc +++ b/qcsrc/server/w_electro.qc @@ -33,7 +33,7 @@ void W_Plasma_Explode (void) 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; @@ -543,6 +543,27 @@ float w_electro(float req) { W_Reload(min(autocvar_g_balance_electro_primary_ammo, autocvar_g_balance_electro_secondary_ammo), autocvar_g_balance_electro_reload_ammo, autocvar_g_balance_electro_reload_time, "weapons/reload.wav"); } + else if (req == WR_SUICIDEMESSAGE) + { + if(w_deathtype & HITTYPE_SECONDARY) + return WEAPON_ELECTRO_SUICIDE_ORBS; + else + return WEAPON_ELECTRO_SUICIDE_BOLT; + } + else if (req == WR_KILLMESSAGE) + { + if(w_deathtype & HITTYPE_SECONDARY) + { + return WEAPON_ELECTRO_MURDER_ORBS; + } + else + { + if(w_deathtype & HITTYPE_BOUNCE) + return WEAPON_ELECTRO_MURDER_COMBO; + else + return WEAPON_ELECTRO_MURDER_BOLT; + } + } return TRUE; } #endif @@ -581,32 +602,6 @@ float w_electro(float req) precache_sound("weapons/electro_impact.wav"); precache_sound("weapons/electro_impact_combo.wav"); } - else if (req == WR_SUICIDEMESSAGE) - { - if(w_deathtype & HITTYPE_SECONDARY) - w_deathtypestring = _("%s could not remember where they put their electro plasma"); - else - w_deathtypestring = _("%s played with electro plasma"); - } - else if (req == WR_KILLMESSAGE) - { - if(w_deathtype & HITTYPE_SECONDARY) - { - if(w_deathtype & HITTYPE_SPLASH) // unchecked: BOUNCE - w_deathtypestring = _("%s just noticed %s's electro plasma"); - else // unchecked: BOUNCE - w_deathtypestring = _("%s got in touch with %s's electro plasma"); - } - else - { - if(w_deathtype & HITTYPE_BOUNCE) // combo - w_deathtypestring = _("%s felt the electrifying air of %s's electro combo"); - else if(w_deathtype & HITTYPE_SPLASH) - w_deathtypestring = _("%s got too close to %s's blue electro bolt"); - else - w_deathtypestring = _("%s was blasted by %s's blue electro bolt"); - } - } return TRUE; } #endif diff --git a/qcsrc/server/w_fireball.qc b/qcsrc/server/w_fireball.qc index 508a8ba1a0..4d243a5135 100644 --- a/qcsrc/server/w_fireball.qc +++ b/qcsrc/server/w_fireball.qc @@ -374,6 +374,24 @@ float w_fireball(float req) { self.fireball_primarytime = time; } + else if (req == WR_SUICIDEMESSAGE) + { + if(w_deathtype & HITTYPE_SECONDARY) + return WEAPON_FIREBALL_SUICIDE_FIREMINE; + else + return WEAPON_FIREBALL_SUICIDE_BLAST; + } + else if (req == WR_KILLMESSAGE) + { + if(w_deathtype & HITTYPE_SECONDARY) + { + return WEAPON_FIREBALL_MURDER_FIREMINE; + } + else + { + return WEAPON_FIREBALL_MURDER_BLAST; + } + } return TRUE; } #endif @@ -399,34 +417,7 @@ float w_fireball(float req) { precache_sound("weapons/fireball_impact2.wav"); } - else if (req == WR_SUICIDEMESSAGE) - { - if(w_deathtype & HITTYPE_SECONDARY) - w_deathtypestring = _("%s forgot about some firemine"); - else - w_deathtypestring = _("%s should have used a smaller gun"); - } - else if (req == WR_KILLMESSAGE) - { - if(w_deathtype & HITTYPE_SECONDARY) - { - w_deathtypestring = _("%s fatefully ignored %s's firemine"); - } - else - { - if(w_deathtype & HITTYPE_BOUNCE) - { - if(w_deathtype & HITTYPE_SPLASH) // BFG effect - w_deathtypestring = _("%s could not hide from %s's fireball"); - else // laser - w_deathtypestring = _("%s saw the pretty lights of %s's fireball"); - } - else if(w_deathtype & HITTYPE_SPLASH) - w_deathtypestring = _("%s got too close to %s's fireball"); - else - w_deathtypestring = _("%s tasted %s's fireball"); - } - } + return TRUE; } #endif diff --git a/qcsrc/server/w_grenadelauncher.qc b/qcsrc/server/w_grenadelauncher.qc index 91b50fe7f7..cdcf841e01 100644 --- a/qcsrc/server/w_grenadelauncher.qc +++ b/qcsrc/server/w_grenadelauncher.qc @@ -12,7 +12,7 @@ void W_Grenade_Explode (void) 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; @@ -32,7 +32,7 @@ void W_Grenade_Explode2 (void) 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; @@ -366,6 +366,20 @@ float w_glauncher(float req) { W_Reload(min(autocvar_g_balance_grenadelauncher_primary_ammo, autocvar_g_balance_grenadelauncher_secondary_ammo), autocvar_g_balance_grenadelauncher_reload_ammo, autocvar_g_balance_grenadelauncher_reload_time, "weapons/reload.wav"); } + else if (req == WR_SUICIDEMESSAGE) + { + if(w_deathtype & HITTYPE_SECONDARY) + return WEAPON_MORTAR_SUICIDE_BOUNCE; + else + return WEAPON_MORTAR_SUICIDE_EXPLODE; + } + else if (req == WR_KILLMESSAGE) + { + if(w_deathtype & HITTYPE_SECONDARY) + return WEAPON_MORTAR_MURDER_BOUNCE; + else + return WEAPON_MORTAR_MURDER_EXPLODE; + } return TRUE; } #endif @@ -384,23 +398,6 @@ float w_glauncher(float req) { precache_sound("weapons/grenade_impact.wav"); } - else if (req == WR_SUICIDEMESSAGE) - { - if(w_deathtype & HITTYPE_SECONDARY) - w_deathtypestring = _("%s didn't see their own grenade"); - else - w_deathtypestring = _("%s blew themself up with their grenadelauncher"); - } - else if (req == WR_KILLMESSAGE) - { - if(w_deathtype & HITTYPE_SPLASH) - if(w_deathtype & HITTYPE_BOUNCE) // (must be secondary then) - w_deathtypestring = _("%s didn't see %s's grenade"); - else // unchecked: SECONDARY - w_deathtypestring = _("%s almost dodged %s's grenade"); - else // unchecked: SECONDARY, BOUNCE - w_deathtypestring = _("%s ate %s's grenade"); - } return TRUE; } #endif diff --git a/qcsrc/server/w_hagar.qc b/qcsrc/server/w_hagar.qc index 55e361ebbc..4d9a0fabe1 100644 --- a/qcsrc/server/w_hagar.qc +++ b/qcsrc/server/w_hagar.qc @@ -236,6 +236,9 @@ void W_Hagar_Attack2_Load_Release (void) 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; @@ -432,6 +435,17 @@ float w_hagar(float req) if not(self.hagar_load) // require releasing loaded rockets first W_Reload(min(autocvar_g_balance_hagar_primary_ammo, autocvar_g_balance_hagar_secondary_ammo), autocvar_g_balance_hagar_reload_ammo, autocvar_g_balance_hagar_reload_time, "weapons/reload.wav"); } + else if (req == WR_SUICIDEMESSAGE) + { + return WEAPON_HAGAR_SUICIDE; + } + else if (req == WR_KILLMESSAGE) + { + if(w_deathtype & HITTYPE_SECONDARY) + return WEAPON_HAGAR_MURDER_BURST; + else + return WEAPON_HAGAR_MURDER_SPRAY; + } return TRUE; } #endif @@ -459,15 +473,6 @@ float w_hagar(float req) precache_sound("weapons/hagexp2.wav"); precache_sound("weapons/hagexp3.wav"); } - else if (req == WR_SUICIDEMESSAGE) - w_deathtypestring = _("%s played with tiny hagar rockets"); - else if (req == WR_KILLMESSAGE) - { - if(w_deathtype & HITTYPE_BOUNCE) // must be secondary; unchecked: SPLASH - w_deathtypestring = _("%s was pummeled with a burst of hagar rockets by %s"); - else // unchecked: SPLASH, SECONDARY - w_deathtypestring = _("%s was pummeled with hagar rockets by %s"); - } return TRUE; } #endif diff --git a/qcsrc/server/w_hlac.qc b/qcsrc/server/w_hlac.qc index 716d0a177c..142a231923 100644 --- a/qcsrc/server/w_hlac.qc +++ b/qcsrc/server/w_hlac.qc @@ -219,6 +219,14 @@ float w_hlac(float req) { W_Reload(min(autocvar_g_balance_hlac_primary_ammo, autocvar_g_balance_hlac_secondary_ammo), autocvar_g_balance_hlac_reload_ammo, autocvar_g_balance_hlac_reload_time, "weapons/reload.wav"); } + else if (req == WR_SUICIDEMESSAGE) + { + return WEAPON_HLAC_SUICIDE; + } + else if (req == WR_KILLMESSAGE) + { + return WEAPON_HLAC_MURDER; + } return TRUE; } #endif @@ -237,10 +245,6 @@ float w_hlac(float req) { precache_sound("weapons/laserimpact.wav"); } - else if (req == WR_SUICIDEMESSAGE) - w_deathtypestring = _("%s should have used a smaller gun"); - else if (req == WR_KILLMESSAGE) - w_deathtypestring = _("%s was cut down with a HLAC by %s"); return TRUE; } #endif diff --git a/qcsrc/server/w_hook.qc b/qcsrc/server/w_hook.qc index c6644f1003..1f9dda17b6 100644 --- a/qcsrc/server/w_hook.qc +++ b/qcsrc/server/w_hook.qc @@ -265,6 +265,14 @@ float w_hook(float req) { self.hook_refire = time; } + else if (req == WR_SUICIDEMESSAGE) + { + return FALSE; + } + else if (req == WR_KILLMESSAGE) + { + return WEAPON_HOOK_MURDER; + } return TRUE; } #endif @@ -283,10 +291,6 @@ float w_hook(float req) { precache_sound("weapons/hookbomb_impact.wav"); } - else if (req == WR_SUICIDEMESSAGE) - w_deathtypestring = _("%s did the impossible"); - else if (req == WR_KILLMESSAGE) - w_deathtypestring = _("%s was caught in %s's hook gravity bomb"); return TRUE; } #endif diff --git a/qcsrc/server/w_laser.qc b/qcsrc/server/w_laser.qc index ecedc89fc1..69dcb17aa5 100644 --- a/qcsrc/server/w_laser.qc +++ b/qcsrc/server/w_laser.qc @@ -291,6 +291,14 @@ float w_laser(float req) { W_Reload(0, autocvar_g_balance_laser_reload_ammo, autocvar_g_balance_laser_reload_time, "weapons/reload.wav"); } + else if (req == WR_SUICIDEMESSAGE) + { + return WEAPON_LASER_SUICIDE; + } + else if (req == WR_KILLMESSAGE) + { + return WEAPON_LASER_MURDER; + } return TRUE; } #endif @@ -309,15 +317,6 @@ float w_laser(float req) { precache_sound("weapons/laserimpact.wav"); } - else if (req == WR_SUICIDEMESSAGE) - w_deathtypestring = _("%s lasered themself to hell"); - else if (req == WR_KILLMESSAGE) - { - if(w_deathtype & HITTYPE_SECONDARY) - w_deathtypestring = _("%s was cut in half by %s's gauntlet"); // unchecked: SPLASH - else - w_deathtypestring = _("%s was lasered to death by %s"); // unchecked: SPLASH - } return TRUE; } #endif diff --git a/qcsrc/server/w_minelayer.qc b/qcsrc/server/w_minelayer.qc index 85ffa6399f..40c60e827e 100644 --- a/qcsrc/server/w_minelayer.qc +++ b/qcsrc/server/w_minelayer.qc @@ -66,7 +66,7 @@ void W_Mine_Explode () 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; @@ -521,6 +521,14 @@ float w_minelayer(float req) { W_Reload(autocvar_g_balance_minelayer_ammo, autocvar_g_balance_minelayer_reload_ammo, autocvar_g_balance_minelayer_reload_time, "weapons/reload.wav"); } + else if (req == WR_SUICIDEMESSAGE) + { + return WEAPON_MINELAYER_SUICIDE; + } + else if (req == WR_KILLMESSAGE) + { + return WEAPON_MINELAYER_MURDER; + } return TRUE; } #endif @@ -539,20 +547,6 @@ float w_minelayer(float req) { precache_sound("weapons/mine_exp.wav"); } - else if (req == WR_SUICIDEMESSAGE) - if(w_deathtype & HITTYPE_BOUNCE) // (remote detonation) - w_deathtypestring = _("%s blew themself up with their minelayer"); - else - w_deathtypestring = _("%s forgot about their mine"); - else if (req == WR_KILLMESSAGE) - { - if(w_deathtype & HITTYPE_BOUNCE) // (remote detonation) - w_deathtypestring = _("%s got too close to %s's mine"); - else if(w_deathtype & HITTYPE_SPLASH) - w_deathtypestring = _("%s almost dodged %s's mine"); - else - w_deathtypestring = _("%s stepped on %s's mine"); - } return TRUE; } #endif diff --git a/qcsrc/server/w_minstanex.qc b/qcsrc/server/w_minstanex.qc index 4031ca8a9d..611319a16c 100644 --- a/qcsrc/server/w_minstanex.qc +++ b/qcsrc/server/w_minstanex.qc @@ -19,15 +19,15 @@ void W_MinstaNex_Attack (void) 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 } } @@ -43,25 +43,25 @@ void W_MinstaNex_Attack (void) { switch(self.team) { - case COLOR_TEAM1: // Red + case NUM_TEAM_1: // Red if(damage_goodhits) WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3RED_HIT"), w_shotorg, v); else WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3RED"), w_shotorg, v); break; - case COLOR_TEAM2: // Blue + case NUM_TEAM_2: // Blue if(damage_goodhits) WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3BLUE_HIT"), w_shotorg, v); else WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3BLUE"), w_shotorg, v); break; - case COLOR_TEAM3: // Yellow + case NUM_TEAM_3: // Yellow if(damage_goodhits) WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3YELLOW_HIT"), w_shotorg, v); else WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3YELLOW"), w_shotorg, v); break; - case COLOR_TEAM4: // Pink + case NUM_TEAM_4: // Pink if(damage_goodhits) WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3PINK_HIT"), w_shotorg, v); else @@ -85,7 +85,7 @@ void minstagib_stop_countdown(entity e) { if (!e.minstagib_needammo) return; - Send_CSQC_Centerprint_Generic_Expire(e, CPID_MINSTA_FINDAMMO); + Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_MINSTA_FINDAMMO); e.minstagib_needammo = FALSE; } void minstagib_ammocheck(void) @@ -93,12 +93,13 @@ void minstagib_ammocheck(void) 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 { @@ -106,60 +107,58 @@ void minstagib_ammocheck(void) 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_CSQC_Centerprint_Generic(self, CPID_MINSTA_FINDAMMO, "^1%d^7 seconds left to find some ammo", 1, 9); + 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_CSQC_Centerprint_Generic(self, CPID_MINSTA_FINDAMMO, "get some ammo or\nyou'll be dead in ^3%d^7 seconds...", 1, 10); + 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; @@ -271,6 +270,14 @@ float w_minstanex(float req) W_Reload(used_ammo, autocvar_g_balance_minstanex_reload_ammo, autocvar_g_balance_minstanex_reload_time, "weapons/reload.wav"); } + else if (req == WR_SUICIDEMESSAGE) + { + return WEAPON_THINKING_WITH_PORTALS; + } + else if (req == WR_KILLMESSAGE) + { + return WEAPON_MINSTANEX_MURDER; + } return TRUE; } #endif @@ -289,10 +296,6 @@ float w_minstanex(float req) { precache_sound("weapons/neximpact.wav"); } - else if (req == WR_SUICIDEMESSAGE) - w_deathtypestring = _("%s is now thinking with portals"); - else if (req == WR_KILLMESSAGE) - w_deathtypestring = _("%s has been vaporized by %s's minstanex"); return TRUE; } #endif diff --git a/qcsrc/server/w_nex.qc b/qcsrc/server/w_nex.qc index 51afdd00f1..23dcce96d8 100644 --- a/qcsrc/server/w_nex.qc +++ b/qcsrc/server/w_nex.qc @@ -66,7 +66,7 @@ void W_Nex_Attack (float issecondary) 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); @@ -233,7 +233,14 @@ float w_nex(float req) { W_Reload(min(autocvar_g_balance_nex_primary_ammo, autocvar_g_balance_nex_secondary_ammo), autocvar_g_balance_nex_reload_ammo, autocvar_g_balance_nex_reload_time, "weapons/reload.wav"); } - + else if (req == WR_SUICIDEMESSAGE) + { + return WEAPON_THINKING_WITH_PORTALS; + } + else if (req == WR_KILLMESSAGE) + { + return WEAPON_NEX_MURDER; + } return TRUE; } #endif @@ -252,10 +259,6 @@ float w_nex(float req) { precache_sound("weapons/neximpact.wav"); } - else if (req == WR_SUICIDEMESSAGE) - w_deathtypestring = _("%s is now thinking with portals"); - else if (req == WR_KILLMESSAGE) - w_deathtypestring = _("%s has been vaporized by %s's nex"); return TRUE; } #endif diff --git a/qcsrc/server/w_porto.qc b/qcsrc/server/w_porto.qc index f95e554b0e..790bcd124c 100644 --- a/qcsrc/server/w_porto.qc +++ b/qcsrc/server/w_porto.qc @@ -375,10 +375,6 @@ float w_porto(float req) { // nothing to do } - else if (req == WR_SUICIDEMESSAGE) - w_deathtypestring = _("%s did the impossible"); - else if (req == WR_KILLMESSAGE) - w_deathtypestring = _("%s felt %s doing the impossible to him"); return TRUE; } #endif diff --git a/qcsrc/server/w_rifle.qc b/qcsrc/server/w_rifle.qc index f707bbd652..749906638b 100644 --- a/qcsrc/server/w_rifle.qc +++ b/qcsrc/server/w_rifle.qc @@ -200,6 +200,27 @@ float w_rifle(float req) { W_Reload(min(autocvar_g_balance_rifle_primary_ammo, autocvar_g_balance_rifle_secondary_ammo), autocvar_g_balance_rifle_reload_ammo, autocvar_g_balance_rifle_reload_time, "weapons/reload.wav"); } + else if (req == WR_SUICIDEMESSAGE) + { + return WEAPON_THINKING_WITH_PORTALS; + } + else if (req == WR_KILLMESSAGE) + { + if(w_deathtype & HITTYPE_SECONDARY) + { + if(w_deathtype & HITTYPE_BOUNCE) + return WEAPON_RIFLE_MURDER_HAIL_PIERCING; + else + return WEAPON_RIFLE_MURDER_HAIL; + } + else + { + if(w_deathtype & HITTYPE_BOUNCE) + return WEAPON_RIFLE_MURDER_PIERCING; + else + return WEAPON_RIFLE_MURDER; + } + } return TRUE; } #endif @@ -227,27 +248,7 @@ float w_rifle(float req) precache_sound("weapons/ric2.wav"); precache_sound("weapons/ric3.wav"); } - else if (req == WR_SUICIDEMESSAGE) - { - w_deathtypestring = _("%s is now thinking with portals"); - } - else if (req == WR_KILLMESSAGE) - { - if(w_deathtype & HITTYPE_SECONDARY) - { - if(w_deathtype & HITTYPE_BOUNCE) - w_deathtypestring = _("%s failed to hide from %s's rifle bullet hail"); - else - w_deathtypestring = _("%s died in %s's rifle bullet hail"); - } - else - { - if(w_deathtype & HITTYPE_BOUNCE) - w_deathtypestring = _("%s failed to hide from %s's rifle"); - else - w_deathtypestring = _("%s was sniped with a rifle by %s"); - } - } + return TRUE; } #endif diff --git a/qcsrc/server/w_rocketlauncher.qc b/qcsrc/server/w_rocketlauncher.qc index add0207d12..250fc0d3be 100644 --- a/qcsrc/server/w_rocketlauncher.qc +++ b/qcsrc/server/w_rocketlauncher.qc @@ -23,7 +23,7 @@ void W_Rocket_Explode () 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; @@ -446,6 +446,17 @@ float w_rlauncher(float req) { W_Reload(autocvar_g_balance_rocketlauncher_ammo, autocvar_g_balance_rocketlauncher_reload_ammo, autocvar_g_balance_rocketlauncher_reload_time, "weapons/reload.wav"); } + else if (req == WR_SUICIDEMESSAGE) + { + return WEAPON_ROCKETLAUNCHER_SUICIDE; + } + else if (req == WR_KILLMESSAGE) + { + if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH)) + return WEAPON_ROCKETLAUNCHER_MURDER_SPLASH; + else + return WEAPON_ROCKETLAUNCHER_MURDER_DIRECT; + } return TRUE; } #endif @@ -464,17 +475,6 @@ float w_rlauncher(float req) { precache_sound("weapons/rocket_impact.wav"); } - else if (req == WR_SUICIDEMESSAGE) - w_deathtypestring = _("%s blew themself up with their rocketlauncher"); - else if (req == WR_KILLMESSAGE) - { - if(w_deathtype & HITTYPE_BOUNCE) // (remote detonation) - w_deathtypestring = _("%s got too close to %s's rocket"); - else if(w_deathtype & HITTYPE_SPLASH) - w_deathtypestring = _("%s almost dodged %s's rocket"); - else - w_deathtypestring = _("%s ate %s's rocket"); - } return TRUE; } #endif diff --git a/qcsrc/server/w_seeker.qc b/qcsrc/server/w_seeker.qc index cd9088e03a..7dbe4aed10 100644 --- a/qcsrc/server/w_seeker.qc +++ b/qcsrc/server/w_seeker.qc @@ -598,20 +598,49 @@ float w_seeker(float req) } else if (req == WR_CHECKAMMO1) { - ammo_amount = self.ammo_rockets >= autocvar_g_balance_seeker_missile_ammo; - ammo_amount += self.(weapon_load[WEP_SEEKER]) >= autocvar_g_balance_seeker_missile_ammo; + if (autocvar_g_balance_seeker_type == 1) + { + ammo_amount = self.ammo_rockets >= autocvar_g_balance_seeker_missile_ammo; + ammo_amount += self.(weapon_load[WEP_SEEKER]) >= autocvar_g_balance_seeker_missile_ammo; + } + else + { + ammo_amount = self.ammo_rockets >= autocvar_g_balance_seeker_tag_ammo; + ammo_amount += self.(weapon_load[WEP_SEEKER]) >= autocvar_g_balance_seeker_tag_ammo; + } + return ammo_amount; } else if (req == WR_CHECKAMMO2) { - ammo_amount = self.ammo_rockets >= autocvar_g_balance_seeker_tag_ammo; - ammo_amount += self.(weapon_load[WEP_SEEKER]) >= autocvar_g_balance_seeker_tag_ammo; + if (autocvar_g_balance_seeker_type == 1) + { + ammo_amount = self.ammo_rockets >= autocvar_g_balance_seeker_tag_ammo; + ammo_amount += self.(weapon_load[WEP_SEEKER]) >= autocvar_g_balance_seeker_tag_ammo; + } + else + { + ammo_amount = self.ammo_rockets >= autocvar_g_balance_seeker_flac_ammo; + ammo_amount += self.(weapon_load[WEP_SEEKER]) >= autocvar_g_balance_seeker_flac_ammo; + } + return ammo_amount; } else if (req == WR_RELOAD) { W_Reload(min(autocvar_g_balance_seeker_missile_ammo, autocvar_g_balance_seeker_tag_ammo), autocvar_g_balance_seeker_reload_ammo, autocvar_g_balance_seeker_reload_time, "weapons/reload.wav"); } + else if (req == WR_SUICIDEMESSAGE) + { + return WEAPON_SEEKER_SUICIDE; + } + else if (req == WR_KILLMESSAGE) + { + if(w_deathtype & HITTYPE_SECONDARY) + return WEAPON_SEEKER_MURDER_TAG; + else + return WEAPON_SEEKER_MURDER_SPRAY; + } return TRUE; } #endif @@ -667,15 +696,6 @@ float w_seeker(float req) precache_sound("weapons/tagexp3.wav"); precache_sound("weapons/tag_impact.wav"); } - else if (req == WR_SUICIDEMESSAGE) - w_deathtypestring = _("%s played with tiny seeker rockets"); - else if (req == WR_KILLMESSAGE) - { - if(w_deathtype & HITTYPE_SECONDARY) - w_deathtypestring = _("%s was tagged with a seeker by %s"); - else - w_deathtypestring = _("%s was pummeled with seeker rockets by %s"); - } return TRUE; } #endif diff --git a/qcsrc/server/w_shotgun.qc b/qcsrc/server/w_shotgun.qc index a4d4139700..1b612057fe 100644 --- a/qcsrc/server/w_shotgun.qc +++ b/qcsrc/server/w_shotgun.qc @@ -85,7 +85,7 @@ void shotgun_meleethink (void) + (v_up * swing_factor * autocvar_g_balance_shotgun_secondary_melee_swing_up) + (v_right * swing_factor * autocvar_g_balance_shotgun_secondary_melee_swing_side)); - WarpZone_traceline_antilag(self.realowner, self.realowner.origin + self.realowner.view_ofs, targpos, FALSE, self.realowner, ANTILAG_LATENCY(self.realowner)); + WarpZone_traceline_antilag(self, self.realowner.origin + self.realowner.view_ofs, targpos, FALSE, self, ANTILAG_LATENCY(self.realowner)); // draw lightning beams for debugging //te_lightning2(world, targpos, self.realowner.origin + self.realowner.view_ofs + v_forward * 5 - v_up * 5); @@ -151,7 +151,7 @@ void W_Shotgun_Attack2 (void) entity meleetemp; meleetemp = spawn(); - meleetemp.owner = meleetemp.realowner = self; + meleetemp.realowner = self; meleetemp.think = shotgun_meleethink; meleetemp.nextthink = time + autocvar_g_balance_shotgun_secondary_melee_delay * W_WeaponRateFactor(); W_SetupShot_Range(self, TRUE, 0, "", 0, autocvar_g_balance_shotgun_secondary_damage, autocvar_g_balance_shotgun_secondary_melee_range); @@ -238,6 +238,17 @@ float w_shotgun(float req) { W_Reload(autocvar_g_balance_shotgun_primary_ammo, autocvar_g_balance_shotgun_reload_ammo, autocvar_g_balance_shotgun_reload_time, "weapons/reload.wav"); } + else if (req == WR_SUICIDEMESSAGE) + { + return WEAPON_THINKING_WITH_PORTALS; + } + else if (req == WR_KILLMESSAGE) + { + if(w_deathtype & HITTYPE_SECONDARY) + return WEAPON_SHOTGUN_MURDER_SLAP; + else + return WEAPON_SHOTGUN_MURDER; + } return TRUE; } #endif @@ -267,15 +278,6 @@ float w_shotgun(float req) precache_sound("weapons/ric2.wav"); precache_sound("weapons/ric3.wav"); } - else if (req == WR_SUICIDEMESSAGE) - w_deathtypestring = _("%s is now thinking with portals"); - else if (req == WR_KILLMESSAGE) - { - if(w_deathtype & HITTYPE_SECONDARY) - w_deathtypestring = _("%2$s slapped %1$s around a bit with a large shotgun"); - else - w_deathtypestring = _("%s was gunned down with a shotgun by %s"); - } return TRUE; } #endif diff --git a/qcsrc/server/w_tuba.qc b/qcsrc/server/w_tuba.qc index d8d53f2bf4..6b3287b59e 100644 --- a/qcsrc/server/w_tuba.qc +++ b/qcsrc/server/w_tuba.qc @@ -186,7 +186,7 @@ float Tuba_GetNote(entity pl, float hittype) // that way, holes in the range of notes are "plugged" if(teamplay) { - if(pl.team == COLOR_TEAM2 || pl.team == COLOR_TEAM4) + if(pl.team == NUM_TEAM_2 || pl.team == NUM_TEAM_4) note += 3; } else @@ -423,65 +423,33 @@ float w_tuba(float req) return TRUE; // TODO use fuel? else if (req == WR_CHECKAMMO2) return TRUE; // TODO use fuel? - return TRUE; -} -#endif -#ifdef CSQC -float w_tuba(float req) -{ - if(req == WR_IMPACTEFFECT) - { - // nothing to do here; particles of tuba are handled differently - } - else if(req == WR_PRECACHE) - { - // nothing to do - } else if (req == WR_SUICIDEMESSAGE) { - float instr; - instr = 0; - if(w_deathtype & HITTYPE_SECONDARY) - instr |= 1; if(w_deathtype & HITTYPE_BOUNCE) - instr |= 2; - switch(instr) - { - default: - case 0: // Tuba - w_deathtypestring = _("%s hurt his own ears with the @!#%%'n Tuba"); - break; - case 1: // Accordeon - w_deathtypestring = _("%s hurt his own ears with the @!#%%'n Accordeon"); - break; - case 2: // Klein Bottle - w_deathtypestring = _("%s hurt his own ears with the @!#%%'n Klein Bottle"); - break; - } + return WEAPON_KLEINBOTTLE_SUICIDE; + else if(w_deathtype & HITTYPE_SECONDARY) + return WEAPON_ACCORDEON_SUICIDE; + else + return WEAPON_TUBA_SUICIDE; } else if (req == WR_KILLMESSAGE) { - float instr; - instr = 0; - if(w_deathtype & HITTYPE_SECONDARY) - instr |= 1; if(w_deathtype & HITTYPE_BOUNCE) - instr |= 2; - switch(instr) - { - default: - case 0: // Tuba - w_deathtypestring = _("%s died of %s's great playing on the @!#%%'n Tuba"); - break; - case 1: // Accordeon - w_deathtypestring = _("%s died of %s's great playing on the @!#%%'n Accordeon"); - break; - case 2: // Klein Bottle - w_deathtypestring = _("%s died of %s's great playing on the @!#%%'n Klein Bottle"); - break; - } + return WEAPON_KLEINBOTTLE_MURDER; + else if(w_deathtype & HITTYPE_SECONDARY) + return WEAPON_ACCORDEON_MURDER; + else + return WEAPON_TUBA_MURDER; } return TRUE; } #endif +#ifdef CSQC +float w_tuba(float req) +{ + // nothing to do here; particles of tuba are handled differently + + return TRUE; +} +#endif #endif diff --git a/qcsrc/server/w_uzi.qc b/qcsrc/server/w_uzi.qc index 525beeacaa..3645b95db8 100644 --- a/qcsrc/server/w_uzi.qc +++ b/qcsrc/server/w_uzi.qc @@ -289,6 +289,17 @@ float w_uzi(float req) { W_Reload(min(max(autocvar_g_balance_uzi_sustained_ammo, autocvar_g_balance_uzi_first_ammo), autocvar_g_balance_uzi_burst_ammo), autocvar_g_balance_uzi_reload_ammo, autocvar_g_balance_uzi_reload_time, "weapons/reload.wav"); } + else if (req == WR_SUICIDEMESSAGE) + { + return WEAPON_THINKING_WITH_PORTALS; + } + else if (req == WR_KILLMESSAGE) + { + if(w_deathtype & HITTYPE_SECONDARY) + return WEAPON_UZI_MURDER_SNIPE; + else + return WEAPON_UZI_MURDER_SPRAY; + } return TRUE; } #endif @@ -314,15 +325,6 @@ float w_uzi(float req) precache_sound("weapons/ric2.wav"); precache_sound("weapons/ric3.wav"); } - else if (req == WR_SUICIDEMESSAGE) - w_deathtypestring = _("%s is now thinking with portals"); - else if (req == WR_KILLMESSAGE) - { - if(w_deathtype & HITTYPE_SECONDARY) - w_deathtypestring = _("%s was sniped by %s's machine gun"); - else - w_deathtypestring = _("%s was riddled full of holes by %s's machine gun"); - } return TRUE; } #endif diff --git a/tooltips.db b/tooltips.db index 1301bda978..0f80a81332 100644 --- a/tooltips.db +++ b/tooltips.db @@ -40,7 +40,6 @@ \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 diff --git a/tooltips.db.it b/tooltips.db.it index 180076f771..e1d1825ddd 100644 --- a/tooltips.db.it +++ b/tooltips.db.it @@ -27,7 +27,7 @@ \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 @@ -40,7 +40,6 @@ \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" diff --git a/unit_fusreac.cfg b/unit_fusreac.cfg index c575f1bf58..c9373f68fe 100644 --- a/unit_fusreac.cfg +++ b/unit_fusreac.cfg @@ -11,3 +11,22 @@ set g_turrets_unit_fusreac_std_target_range_min 1 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