]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into z411/bai-server
authorz411 <z411@omaera.org>
Wed, 27 Mar 2024 22:40:05 +0000 (19:40 -0300)
committerz411 <z411@omaera.org>
Wed, 27 Mar 2024 22:49:25 +0000 (19:49 -0300)
121 files changed:
commands.cfg
gamemodes-server.cfg
gfx/menu/luma/gametype_mmm.tga [new file with mode: 0644]
gfx/menu/luma/gametype_sv.tga [new file with mode: 0644]
gfx/menu/luminos/gametype_mmm.tga [new file with mode: 0644]
gfx/menu/luminos/gametype_sv.tga [new file with mode: 0644]
gfx/menu/wickedx/gametype_mmm.tga [new file with mode: 0644]
gfx/menu/wickedx/gametype_sv.tga [new file with mode: 0644]
gfx/menu/xaw/gametype_mmm.tga [new file with mode: 0644]
gfx/menu/xaw/gametype_sv.tga [new file with mode: 0644]
notifications.cfg
qcsrc/client/announcer.qc
qcsrc/client/hud/hud.qh
qcsrc/client/hud/panel/_mod.inc
qcsrc/client/hud/panel/_mod.qh
qcsrc/client/hud/panel/centerprint.qc
qcsrc/client/hud/panel/centerprint.qh
qcsrc/client/hud/panel/chat.qc
qcsrc/client/hud/panel/healtharmor.qc
qcsrc/client/hud/panel/infomessages.qc
qcsrc/client/hud/panel/modicons.qc
qcsrc/client/hud/panel/quickmenu.qc
qcsrc/client/hud/panel/score.qc
qcsrc/client/hud/panel/scoreboard.qc
qcsrc/client/hud/panel/spect.qc [new file with mode: 0644]
qcsrc/client/hud/panel/spect.qh [new file with mode: 0644]
qcsrc/client/hud/panel/timer.qc
qcsrc/client/hud/panel/weapons.qc
qcsrc/client/main.qc
qcsrc/client/main.qh
qcsrc/client/view.qc
qcsrc/common/_all.inc
qcsrc/common/announcer.qc [new file with mode: 0644]
qcsrc/common/colors.qc [new file with mode: 0644]
qcsrc/common/ent_cs.qc
qcsrc/common/ent_cs.qh
qcsrc/common/gamemodes/gamemode/clanarena/cl_clanarena.qc
qcsrc/common/gamemodes/gamemode/clanarena/cl_clanarena.qh
qcsrc/common/gamemodes/gamemode/clanarena/clanarena.qh
qcsrc/common/gamemodes/gamemode/clanarena/sv_clanarena.qc
qcsrc/common/gamemodes/gamemode/clanarena/sv_clanarena.qh
qcsrc/common/gamemodes/gamemode/ctf/sv_ctf.qc
qcsrc/common/gamemodes/gamemode/ctf/sv_ctf.qh
qcsrc/common/gamemodes/gamemode/deathmatch/sv_deathmatch.qc
qcsrc/common/gamemodes/gamemode/duel/sv_duel.qc
qcsrc/common/gamemodes/gamemode/freezetag/cl_freezetag.qc
qcsrc/common/gamemodes/gamemode/freezetag/cl_freezetag.qh
qcsrc/common/gamemodes/gamemode/freezetag/freezetag.qh
qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qc
qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qh
qcsrc/common/gamemodes/gamemode/race/sv_race.qc
qcsrc/common/gamemodes/gamemode/tdm/sv_tdm.qc
qcsrc/common/items/inventory.qh
qcsrc/common/mapinfo.qh
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/mutators/mutator/_mod.inc
qcsrc/common/mutators/mutator/_mod.qh
qcsrc/common/mutators/mutator/attackertext/_mod.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/attackertext/_mod.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/attackertext/attackertext.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/attackertext/attackertext.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/attackertext/cl_attackertext.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/attackertext/cl_attackertext.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/attackertext/sv_attackertext.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/attackertext/sv_attackertext.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/bloodloss/bloodloss.qc
qcsrc/common/mutators/mutator/buffs/sv_buffs.qc
qcsrc/common/mutators/mutator/campcheck/sv_campcheck.qc
qcsrc/common/mutators/mutator/instagib/sv_instagib.qc
qcsrc/common/mutators/mutator/itemstime/itemstime.qc
qcsrc/common/mutators/mutator/itemstime/itemstime.qh
qcsrc/common/mutators/mutator/overkill/oknex.qc
qcsrc/common/net_linked.qh
qcsrc/common/notifications/all.inc
qcsrc/common/notifications/all.qc
qcsrc/common/notifications/all.qh
qcsrc/common/replicate.qh
qcsrc/common/scores.qh
qcsrc/common/sounds/all.inc
qcsrc/common/state.qc
qcsrc/common/stats.qh
qcsrc/common/teams.qh
qcsrc/common/util.qc
qcsrc/common/weapons/weapon/devastator.qc
qcsrc/common/weapons/weapon/electro.qc
qcsrc/common/weapons/weapon/mortar.qc
qcsrc/common/weapons/weapon/shotgun.qc
qcsrc/common/weapons/weapon/vaporizer.qc
qcsrc/common/weapons/weapon/vortex.qc
qcsrc/common/weapons/weapon/vortex.qh
qcsrc/ecs/systems/sv_physics.qc
qcsrc/server/chat.qc
qcsrc/server/chat.qh
qcsrc/server/client.qc
qcsrc/server/client.qh
qcsrc/server/clientkill.qc
qcsrc/server/command/banning.qc
qcsrc/server/command/cmd.qc
qcsrc/server/command/common.qc
qcsrc/server/command/sv_cmd.qc
qcsrc/server/command/vote.qc
qcsrc/server/command/vote.qh
qcsrc/server/damage.qc
qcsrc/server/damage.qh
qcsrc/server/ipban.qc
qcsrc/server/ipban.qh
qcsrc/server/items/items.qc
qcsrc/server/mutators/events.qh
qcsrc/server/round_handler.qc
qcsrc/server/round_handler.qh
qcsrc/server/scores.qc
qcsrc/server/scores.qh
qcsrc/server/teamplay.qc
qcsrc/server/teamplay.qh
qcsrc/server/weapons/accuracy.qc
qcsrc/server/weapons/accuracy.qh
qcsrc/server/weapons/tracing.qc
qcsrc/server/weapons/weaponsystem.qc
qcsrc/server/world.qc
qcsrc/server/world.qh
xonotic-server.cfg

index f7cc14eee8221306fbdf41a04c72d673e4293748..6cff034afe327c9016aa38abdde40e7cc3515f39 100644 (file)
@@ -273,6 +273,7 @@ alias settemp_restore "qc_cmd_svcl settemp_restore"
 // ===================================
 alias ban                  "qc_cmd_sv     ban                  ${* ?}" // Ban an IP address or a range of addresses (like 1.2.3)
 alias banlist              "qc_cmd_sv     banlist              ${* ?}" // List all existing bans
+alias kickkick             "qc_cmd_sv     kickkick             ${* ?}" // Disconnect a client
 alias kickban              "qc_cmd_sv     kickban              ${* ?}" // Disconnect a client and ban it at the same time
 alias mute                 "qc_cmd_sv     mute                 ${* ?}" // Disallow a client from talking by muting them
 alias unban                "qc_cmd_sv     unban                ${* ?}" // Remove an existing ban
index a859acbded174ebaf334b8725ea30439b342c45a..8863cc496f1ad6737628b5f59eb74357ce3e9c51 100644 (file)
@@ -262,6 +262,7 @@ set g_ca_spectate_enemies 0 "allow eliminated players to spectate enemy players
 set g_ca_warmup 10 "time players get to run around before the round starts"
 set g_ca_damage2score 100  "every this amount of damage done give players 1 point"
 set g_ca_round_timelimit 180 "round time limit in seconds"
+set g_ca_round_stop 0 "freeze the game after round stops" // BaI mod
 set g_ca_teams_override 0
 set g_ca_team_spawns 0 "when 1, players spawn from the team spawnpoints of the map, if any"
 set g_ca_teams 0
@@ -401,7 +402,8 @@ set g_domination_warmup 5 "time players have to wait before the round starts"
 //  freezetag
 // ===========
 set g_freezetag 0 "Freeze Tag: Freeze the opposing team(s) to win, unfreeze teammates by standing next to them"
-set g_freezetag_warmup 10 "time players get to run around before the round starts"
+// BaI mod changes this
+set g_freezetag_warmup 5 "time players get to run around before the round starts"
 set 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)"
 set 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)"
 set g_freezetag_revive_speed 0.4 "Speed for reviving a frozen teammate if g_freezetag_revive_time_to_score is off"
@@ -412,17 +414,21 @@ set g_freezetag_revive_nade 1 "Enable reviving from own nade explosion"
 set g_freezetag_revive_nade_health 40 "Amount of health player has if they revived from their own nade explosion"
 set g_freezetag_revive_time_to_score 1.5 "every this amount of seconds give players reviving a frozen teammate 1 point"
 set g_freezetag_round_timelimit 360 "round time limit in seconds"
+set g_freezetag_round_stop 0 "freeze game when round ends" // BaI mod
+set g_freezetag_round_respawn 0 // BaI mod
 set g_freezetag_revive_auto 1 "automatically revive frozen players after some time (g_freezetag_frozen_maxtime)"
 set g_freezetag_revive_auto_progress 1 "start the automatic reviving progress as soon as the player gets frozen"
 set g_freezetag_revive_auto_reducible 1 "reduce auto-revival time when frozen players are hit by enemies; set to -1 to reduce it even when they are hit by teammates"
 set g_freezetag_revive_auto_reducible_forcefactor 0.01 "hit force to time reduction conversion factor"
 set g_freezetag_revive_auto_reducible_maxforce 400 "max force considered at once"
+set g_freezetag_revive_respawn 1 "respawn when reviving" // BaI mod
 set g_freezetag_revive_spawnshield 1 "apply spawnshield for this time in seconds after the player has been revived"
 set g_freezetag_frozen_maxtime 60 "frozen players will be automatically unfrozen after this time in seconds"
 set g_freezetag_teams_override 0
 set g_freezetag_team_spawns 0 "when 1, players spawn from the team spawnpoints of the map, if any"
 set g_freezetag_teams 0
-set g_freezetag_weaponarena "most_available" "starting weapons - takes the same options as g_weaponarena"
+// BaI mod changes this
+set g_freezetag_weaponarena "0" "starting weapons - takes the same options as g_weaponarena"
 
 
 // ==========
@@ -616,6 +622,27 @@ set g_duel_not_dm_maps 0 "when this is set, DM maps will NOT be listed in duel"
 // ==============================
 //  free for all and team mayhem
 // ==============================
+<<<<<<< HEAD
+set g_mayhem 0 "Mayhem: Compete for the most damage dealt and frags in this chaotic mayhem!"
+set g_tmayhem 0 "Team Mayhem: Compete with your team for the most damage dealt and frags in this chaotic mayhem!"
+
+set g_mayhem_scoringmethod 1 "1: By default 25% of the score is based on kills and 75% of it is based on damage. 2: 100% frags. 3: 100% damage."
+set g_tmayhem_scoringmethod 1 "1: By default 25% of the score is based on kills and 75% of it is based on damage. 2: 100% frags. 3: 100% damage."
+set g_mayhem_scoringmethod_1_damage_weight 0.75 "for the first scoring method how much is damage equal to player's spawning health worth in score"
+set g_tmayhem_scoringmethod_1_damage_weight 0.75 "for the first scoring method how much is damage equal to player's spawning health worth in score"
+set g_mayhem_scoringmethod_1_disable_selfdamage2score 0 "disable reducing score with self damage at the cost of full penalty for suicides regardless of how much health was lost suiciding"
+set g_tmayhem_scoringmethod_1_disable_selfdamage2score 0 "disable reducing score with self damage at the cost of full penalty for suicides regardless of how much health was lost suiciding"
+set g_mayhem_scoringmethod_1_frag_weight 0.25 "for the first scoring method how much is a frag worth in score"
+set g_tmayhem_scoringmethod_1_frag_weight 0.25 "for the first scoring method how much is a frag worth in score"
+
+set g_mayhem_fraglimit 30 "Team Mayhem basis for how many frags until the match ends, edit this over point_limit preferably"
+set g_tmayhem_fraglimit 50 "Team Mayhem basis for how many frags until the match ends, edit this over point_limit preferably"
+
+set g_mayhem_visual_score_limit 1000 "Mayhem visual score limit overriding the mapinfo specified one"
+set g_tmayhem_visual_score_limit 1000 "Team Mayhem visual score limit overriding the mapinfo specified one"
+
+set g_tmayhem_score_leadlimit -1 "Team Mayhem score lead limit(based on tmayhem_visual_score_limit, not tmayhem_fraglimit) overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
+=======
 set g_mayhem 0 "Mayhem: Compete for the most damage dealt and kills in this chaotic mayhem!"
 set g_tmayhem 0 "Team Mayhem: Compete with your team for the most damage dealt and kills in this chaotic mayhem!"
 
@@ -632,6 +659,7 @@ set g_mayhem_point_limit -1 "Mayhem score limit overriding the mapinfo specified
 set g_mayhem_point_leadlimit -1 "Mayhem score lead limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
 set g_tmayhem_point_limit -1 "Team Mayhem score limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
 set g_tmayhem_point_leadlimit -1 "Team Mayhem score lead limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
+>>>>>>> master
 
 set g_mayhem_weaponarena "most_available" "starting weapons - takes the same options as g_weaponarena"
 set g_tmayhem_weaponarena "most_available" "starting weapons - takes the same options as g_weaponarena"
diff --git a/gfx/menu/luma/gametype_mmm.tga b/gfx/menu/luma/gametype_mmm.tga
new file mode 100644 (file)
index 0000000..481c621
Binary files /dev/null and b/gfx/menu/luma/gametype_mmm.tga differ
diff --git a/gfx/menu/luma/gametype_sv.tga b/gfx/menu/luma/gametype_sv.tga
new file mode 100644 (file)
index 0000000..050fb7b
Binary files /dev/null and b/gfx/menu/luma/gametype_sv.tga differ
diff --git a/gfx/menu/luminos/gametype_mmm.tga b/gfx/menu/luminos/gametype_mmm.tga
new file mode 100644 (file)
index 0000000..8bacd80
Binary files /dev/null and b/gfx/menu/luminos/gametype_mmm.tga differ
diff --git a/gfx/menu/luminos/gametype_sv.tga b/gfx/menu/luminos/gametype_sv.tga
new file mode 100644 (file)
index 0000000..c548665
Binary files /dev/null and b/gfx/menu/luminos/gametype_sv.tga differ
diff --git a/gfx/menu/wickedx/gametype_mmm.tga b/gfx/menu/wickedx/gametype_mmm.tga
new file mode 100644 (file)
index 0000000..8bacd80
Binary files /dev/null and b/gfx/menu/wickedx/gametype_mmm.tga differ
diff --git a/gfx/menu/wickedx/gametype_sv.tga b/gfx/menu/wickedx/gametype_sv.tga
new file mode 100644 (file)
index 0000000..c548665
Binary files /dev/null and b/gfx/menu/wickedx/gametype_sv.tga differ
diff --git a/gfx/menu/xaw/gametype_mmm.tga b/gfx/menu/xaw/gametype_mmm.tga
new file mode 100644 (file)
index 0000000..938b529
Binary files /dev/null and b/gfx/menu/xaw/gametype_mmm.tga differ
diff --git a/gfx/menu/xaw/gametype_sv.tga b/gfx/menu/xaw/gametype_sv.tga
new file mode 100644 (file)
index 0000000..debbce0
Binary files /dev/null and b/gfx/menu/xaw/gametype_sv.tga differ
index 22a4e70a31403caeaef852e66b96d1c74ae9f011..c5e9b02c1b159f031f341c2cfb7b55a658cf6d8e 100644 (file)
 // ********************************************** //
 
 // MSG_ANNCE notifications:
+seta notification_ANNCE_ACCIDENT "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_ACHIEVEMENT_ACCURACY "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_ACHIEVEMENT_AIRSHOT "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_ACHIEVEMENT_AMAZING "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_ACHIEVEMENT_ASSIST "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_ACHIEVEMENT_AWESOME "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_ACHIEVEMENT_BOTLIKE "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_ACHIEVEMENT_DAMAGE "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_ACHIEVEMENT_DEFENSE "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_ACHIEVEMENT_ELECTROBITCH "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_ACHIEVEMENT_EXCELLENT "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_ACHIEVEMENT_IMPRESSIVE "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_ACHIEVEMENT_PERFECT "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_ACHIEVEMENT_TELEFRAG "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_ACHIEVEMENT_YODA "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_ALONE "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_BEGIN "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_CTF_PICKUP_ENEMY "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_CTF_PICKUP "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_CTF_PICKUP_TEAM "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_CTF_PICKUP_YOU "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_CTF_RETURN_ENEMY "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_CTF_RETURN "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_CTF_RETURN_TEAM "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_FIRSTBLOOD "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_HEADSHOT "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_HUMILIATION "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_INSTAGIB_LASTSECOND "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_INSTAGIB_NARROWLY "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_INSTAGIB_TERMINATED "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
@@ -28,10 +46,10 @@ seta notification_ANNCE_KILLSTREAK_03 "1" "0 = disabled, 1 = enabled if gentle m
 seta notification_ANNCE_KILLSTREAK_05 "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_KILLSTREAK_10 "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_KILLSTREAK_15 "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
-seta notification_ANNCE_KILLSTREAK_20 "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
-seta notification_ANNCE_KILLSTREAK_25 "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
-seta notification_ANNCE_KILLSTREAK_30 "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
-seta notification_ANNCE_MULTIFRAG "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_LEAD_GAINED "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_LEAD_LOST "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_LEAD_TIED "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_MULTIFRAG "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_NUM_1 "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_NUM_10 "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_NUM_2 "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
@@ -52,6 +70,16 @@ seta notification_ANNCE_NUM_GAMESTART_6 "0" "0 = disabled, 1 = enabled if gentle
 seta notification_ANNCE_NUM_GAMESTART_7 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_NUM_GAMESTART_8 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_NUM_GAMESTART_9 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_NUM_IDLE_1 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_NUM_IDLE_10 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_NUM_IDLE_2 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_NUM_IDLE_3 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_NUM_IDLE_4 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_NUM_IDLE_5 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_NUM_IDLE_6 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_NUM_IDLE_7 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_NUM_IDLE_8 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_NUM_IDLE_9 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_NUM_KILL_1 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_NUM_KILL_10 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_NUM_KILL_2 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
@@ -82,12 +110,27 @@ seta notification_ANNCE_NUM_ROUNDSTART_6 "0" "0 = disabled, 1 = enabled if gentl
 seta notification_ANNCE_NUM_ROUNDSTART_7 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_NUM_ROUNDSTART_8 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_NUM_ROUNDSTART_9 "0" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_OVERTIME "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_PREPARE "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_PREPARE_TEAM "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_REMAINING_FRAG_1 "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_REMAINING_FRAG_2 "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_REMAINING_FRAG_3 "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_REMAINING_MIN_1 "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_REMAINING_MIN_5 "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_ROUND_OVER "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_ROUND_TEAM_WIN "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_ROUND_TIED "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_SUDDENDEATH "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_SUICIDE "1" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_TEAM_LEADS_ENEMY "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_TEAM_LEADS "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_TEAM_LEADS_TEAM "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_TEAM_LEADS_TIED "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_TEAM_SCORES_ENEMY "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_TEAM_SCORES "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_TEAM_SCORES_TEAM "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
+seta notification_ANNCE_TEAM_WINS "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_TIMEOUT "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_VOTE_ACCEPT "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
 seta notification_ANNCE_VOTE_CALL "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
@@ -234,6 +277,7 @@ seta notification_INFO_JETPACK_NOFUEL "1" "0 = off, 1 = print to console, 2 = pr
 seta notification_INFO_JOIN_CONNECT "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_JOIN_PLAY "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_JOIN_PLAY_TEAM "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+seta notification_INFO_JOIN_WANTS_TEAM "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_KEEPAWAY_DROPPED "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_KEEPAWAY_PICKUP "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_KEYHUNT_CAPTURE "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
@@ -246,6 +290,7 @@ seta notification_INFO_LMS_NOLIVES "1" "0 = off, 1 = print to console, 2 = print
 seta notification_INFO_MINIGAME_INVITE "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_MONSTERS_DISABLED "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_MOVETOSPEC_IDLING "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+seta notification_INFO_MOVETOSPEC_REMOVE "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_NEXBALL_RETURN_HELD "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_ONSLAUGHT_CAPTURE "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_ONSLAUGHT_CAPTURE_NONAME "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
@@ -258,10 +303,12 @@ seta notification_INFO_POWERUP_SHIELD "1" "0 = off, 1 = print to console, 2 = pr
 seta notification_INFO_POWERUP_SPEED "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_POWERUP_STRENGTH "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_QUIT_DISCONNECT "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+seta notification_INFO_QUIT_KICK "2" "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" "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" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_QUIT_KICK_TEAMKILL "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_QUIT_PLAYBAN_TEAMKILL "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+seta notification_INFO_QUIT_QUEUE "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_QUIT_SPECTATE "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_RACE_ABANDONED "1" "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" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
@@ -274,6 +321,7 @@ seta notification_INFO_RACE_NEW_MISSING_UID "1" "0 = off, 1 = print to console,
 seta notification_INFO_RACE_NEW_SET "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_ROUND_OVER "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_ROUND_PLAYER_WIN "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+seta notification_INFO_ROUND_TEAM_SCORES "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_ROUND_TEAM_WIN "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_ROUND_TIED "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_SCORES "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
@@ -399,6 +447,8 @@ seta notification_CENTER_CTF_PICKUP_VISIBLE "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_CTF_RETURN "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_CTF_STALEMATE_CARRIER "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_CTF_STALEMATE_OTHER "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_DEATH_MURDER_DM "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_DEATH_MURDER_DUEL "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_DEATH_MURDER_FRAG "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_DEATH_MURDER_FRAGGED "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_DEATH_MURDER_FRAGGED_FIRE "1" "0 = off, 1 = centerprint"
@@ -483,6 +533,7 @@ seta notification_CENTER_JOIN_NOSPAWNS "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_JOIN_PLAYBAN "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_JOIN_PREVENT "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_JOIN_PREVENT_MINIGAME "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_JOIN_PREVENT_QUEUE "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_KEEPAWAY_DROPPED "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_KEEPAWAY_PICKUP "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_KEEPAWAY_PICKUP_SELF "1" "0 = off, 1 = centerprint"
@@ -497,8 +548,10 @@ seta notification_CENTER_LMS_NOLIVES "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_LMS_VISIBLE_LEADER "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_LMS_VISIBLE_OTHER "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_MISSING_PLAYERS "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_MISSING_READY "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_MISSING_TEAMS "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_MOVETOSPEC_IDLING "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_MOVETOSPEC_REMOVE "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_NADE_BONUS "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_NADE_THROW "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_NIX_COUNTDOWN "1" "0 = off, 1 = centerprint"
@@ -532,6 +585,7 @@ seta notification_CENTER_RACE_FINISHLAP "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_ROUND_OVER "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_ROUND_PLAYER_WIN "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_ROUND_TEAM_LOSS "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_ROUND_TEAM_SCORES "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_ROUND_TEAM_WIN "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_ROUND_TIED "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_SEQUENCE_COMPLETED "1" "0 = off, 1 = centerprint"
@@ -550,6 +604,7 @@ seta notification_CENTER_TEAMCHANGE_SPECTATE "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_TEAMCHANGE_SUICIDE "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_TIMEOUT_BEGINNING "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_TIMEOUT_ENDING "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_TIMEOUT_ONGOING "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_VEHICLE_ENTER "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_VEHICLE_ENTER_GUNNER "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_VEHICLE_ENTER_STEAL "1" "0 = off, 1 = centerprint"
@@ -757,6 +812,27 @@ seta notification_CHOICE_TYPEFRAG_ALLOWED "1" "Allow choice for this notificatio
 seta notification_CHOICE_TYPEFRAGGED "1" "Choice for this notification 0 = off, 1 = default message, 2 = verbose message"
 seta notification_CHOICE_TYPEFRAGGED_ALLOWED "1" "Allow choice for this notification 0 = off, 1 = only in warmup mode, 2 = always"
 
+// MSG_MEDAL notifications (count = 19):
+seta notification_MEDAL_ACCURACY "2" "Enable this multiple notification"
+seta notification_MEDAL_AIRSHOT "2" "Enable this multiple notification"
+seta notification_MEDAL_ASSIST "2" "Enable this multiple notification"
+seta notification_MEDAL_CAPTURE "2" "Enable this multiple notification"
+seta notification_MEDAL_DAMAGE "2" "Enable this multiple notification"
+seta notification_MEDAL_DEFENSE "2" "Enable this multiple notification"
+seta notification_MEDAL_ELECTROBITCH "2" "Enable this multiple notification"
+seta notification_MEDAL_EXCELLENT "2" "Enable this multiple notification"
+seta notification_MEDAL_FIRSTBLOOD "2" "Enable this multiple notification"
+seta notification_MEDAL_HEADSHOT "2" "Enable this multiple notification"
+seta notification_MEDAL_HUMILIATION "2" "Enable this multiple notification"
+seta notification_MEDAL_IMPRESSIVE "2" "Enable this multiple notification"
+seta notification_MEDAL_KILLSTREAK_03 "2" "Enable this multiple notification"
+seta notification_MEDAL_KILLSTREAK_05 "2" "Enable this multiple notification"
+seta notification_MEDAL_KILLSTREAK_10 "2" "Enable this multiple notification"
+seta notification_MEDAL_KILLSTREAK_15 "2" "Enable this multiple notification"
+seta notification_MEDAL_PERFECT "2" "Enable this multiple notification"
+seta notification_MEDAL_TELEFRAG "2" "Enable this multiple notification"
+seta notification_MEDAL_YODA "2" "Enable this multiple notification"
+
 // HARD CODED notification variables:
 seta notification_allow_chatboxprint "1" "Allow INFO notifications to be printed to chat box 0 = do not allow, 1 = allow only if allowed by individual notification_INFO* cvars, 2 = force all INFO notifications to be printed to the chatbox"
 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"
index cc85f31ccab7b62ee8fc9bfadcb55e47db795b8f..43b8347dc00605555d66d344a873258d87443e6f 100644 (file)
@@ -59,7 +59,9 @@ void Announcer_Countdown(entity this)
 {
        float starttime = STAT(GAMESTARTTIME);
        float roundstarttime = STAT(ROUNDSTARTTIME);
-       if(roundstarttime == -1)
+       bool game_timeout = (STAT(TIMEOUT_LAST) > 0);
+       
+       if(roundstarttime == -1 || game_timeout)
        {
                Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_ROUNDSTOP);
                delete(this);
@@ -72,6 +74,7 @@ void Announcer_Countdown(entity this)
        float countdown = (inround ? roundstarttime - time : starttime - time);
        float countdown_rounded = floor(0.5 + countdown);
 
+       if (time >= starttime) centerprint_ClearTitle();
        if (starttime != prev_starttime || roundstarttime != prev_roundstarttime || prev_inround != inround)
                this.skin = 0; // restart centerprint countdown
 
@@ -163,7 +166,10 @@ void Announcer_Gamestart()
                                        centerprint_SetTitle(strcat("^BG", MapInfo_Type_ToText(gametype))); // Show game type as title
 
                                if(time + 5.0 < startTime) // if connecting to server while restart was active don't always play prepareforbattle
-                                       Local_Notification(MSG_ANNCE, ANNCE_PREPARE);
+                                       if(teamplay)
+                                               Local_Notification(MSG_ANNCE, ANNCE_PREPARE_TEAM);
+                                       else
+                                               Local_Notification(MSG_ANNCE, ANNCE_PREPARE);
                        }
 
                        announcer_countdown.nextthink = startTime - floor(startTime - time + 0.5); //synchronize nextthink to startTime
index 312aaea99be3a978b1ca78e996452cea18e5479d..be15ac3ae7982cec440ee85a0e4ee745d6021cf9 100644 (file)
@@ -213,6 +213,9 @@ vector hud_dynamic_shake_realofs;
 float hud_dynamic_shake_factor;
 float hud_dynamic_shake_time;
 
+bool autocvar_hud_panel_spect_scores = true; //LegendGuard adds a bool to enable/disable score display HUD 06-04-2021
+bool autocvar_hud_panel_spect_playername = true; //LegendGuard adds a bool to enable/disable player name display HUD 06-04-2021
+
 // shared across viewmodel effects and dynamic hud code
 vector cl_followmodel_ofs;
 float cl_followmodel_time;
@@ -278,6 +281,7 @@ REGISTER_HUD_PANEL(QUICKMENU,       HUD_QuickMenu,      PANEL_CONFIG_MAIN
 REGISTER_HUD_PANEL(SCOREBOARD,      Scoreboard_Draw,    PANEL_CONFIG_NO                          , PANEL_SHOW_MAINGAME | PANEL_SHOW_MINIGAME | PANEL_SHOW_MAPVOTE | PANEL_SHOW_WITH_SB) // SCOREBOARD
 REGISTER_HUD_PANEL(STRAFEHUD,       HUD_StrafeHUD,      PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                                                ) // STRAFEHUD
 REGISTER_HUD_PANEL(PICKUP,          HUD_Pickup,         PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                                                ) // PICKUP
+REGISTER_HUD_PANEL(SPECTHUD,        HUD_SpectHUD,       PANEL_CONFIG_NO   | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                                                ) // SPECTHUD
 // always add new panels to the end of list
 
 // Because calling lots of functions in QC apparently cuts fps in half on many machines:
index 9f6c7fb5c4e9dd63322a07ee3be2cc5b73c6df88..626a4bf15136809214919ee380cd7b9880759257 100644 (file)
@@ -16,6 +16,7 @@
 #include <client/hud/panel/racetimer.qc>
 #include <client/hud/panel/radar.qc>
 #include <client/hud/panel/score.qc>
+#include <client/hud/panel/spect.qc>
 #include <client/hud/panel/scoreboard.qc>
 #include <client/hud/panel/strafehud.qc>
 #include <client/hud/panel/timer.qc>
index 4f901379e8e46618242acd1aba3a6a614002a24e..6fe81e89aa5d29b7d56b2e7b05d6097075396069 100644 (file)
@@ -16,6 +16,7 @@
 #include <client/hud/panel/racetimer.qh>
 #include <client/hud/panel/radar.qh>
 #include <client/hud/panel/score.qh>
+#include <client/hud/panel/spect.qh>
 #include <client/hud/panel/scoreboard.qh>
 #include <client/hud/panel/strafehud.qh>
 #include <client/hud/panel/timer.qh>
index 1e388c4d8c6dd165a1fbdacc3ccb7d52e7ab63df..3dd6bdc6a9d9b10fa1080e65550b593ba4189c07 100644 (file)
@@ -45,6 +45,10 @@ float centerprint_expire_time[CENTERPRINT_MAX_MSGS];
 int centerprint_countdown_num[CENTERPRINT_MAX_MSGS];
 bool centerprint_showing;
 
+float centerprint_medal_expire_time;
+string centerprint_medal_icon;
+float centerprint_medal_times;
+
 string centerprint_title;
 string centerprint_title_left;
 string centerprint_title_right;
@@ -151,6 +155,21 @@ void centerprint_KillAll()
        }
 }
 
+void centerprint_Medal(string icon, float times)
+{
+       if(!autocvar_hud_panel_centerprint_medals) return;
+
+       //LOG_INFOF("centerprint_Medal: icon: %s times: %d", icon, times);
+       //centerprint_medal_expire_time = time + autocvar_hud_panel_centerprint_time;
+       centerprint_medal_expire_time = time + MSG_MEDAL_TIME;
+       centerprint_medal_times = times;
+       if(centerprint_medal_icon)
+               strunzone(centerprint_medal_icon);
+       centerprint_medal_icon = strzone(strcat("gfx/medal/", icon));
+
+       centerprint_showing = true;
+}
+
 void centerprint_SetDuelTitle(string left, string right)
 {
        float namesize = autocvar_hud_panel_scoreboard_namesize * hud_fontsize.x;
@@ -262,9 +281,46 @@ void HUD_CenterPrint()
        bool all_messages_expired = true;
 
        pos = panel_pos;
+
        if (autocvar_hud_panel_centerprint_flip)
                pos.y += panel_size.y;
        align = bound(0, autocvar_hud_panel_centerprint_align, 1);
+       
+       // z411 draw medals first
+       if (autocvar_hud_panel_centerprint_medals && time < centerprint_medal_expire_time) {
+               float height = vid_conheight/50 * 4;
+               pos.y -= height;
+
+               if(time < centerprint_medal_expire_time - MSG_MEDAL_FADE_TIME)
+                       a = 1;
+               else
+                       a = (centerprint_medal_expire_time - time) / MSG_MEDAL_FADE_TIME;
+               
+               vector tmp_in = pos;
+                       
+               vector mysize = draw_getimagesize(centerprint_medal_icon);
+               vector newsize = vec2(height*(mysize.x/mysize.y), height);
+               vector fontsize = '1 1 0' * (newsize.y/2);
+               
+               tmp_in.x += (panel_size.x - newsize.x) / 2; // center medal icon
+               
+               if(centerprint_medal_times < autocvar_hud_panel_centerprint_medals_max) {
+                       tmp_in.x -= ((newsize.x * 1.1) * (centerprint_medal_times - 1) / 2);
+                       for(int t = 0; t < centerprint_medal_times; t++) {
+                               drawpic(tmp_in, centerprint_medal_icon, newsize, '1 1 1', a, DRAWFLAG_NORMAL);
+                               tmp_in.x += newsize.x * 1.1;
+                       }
+               } else {
+                       drawpic(tmp_in, centerprint_medal_icon, newsize, '1 1 1', a, DRAWFLAG_NORMAL);
+                       tmp_in.x += newsize.x + fontsize.x * 0.25; // draw times next to it
+                       tmp_in.y += (newsize.y - fontsize.y) / 2;
+                       drawstring(tmp_in, ftos(centerprint_medal_times), fontsize, '1 1 1', a, DRAWFLAG_NORMAL);
+               }
+
+               pos.y += height;
+               
+               all_messages_expired = false;
+       }
 
        // Show title if available
        if(centerprint_title != "" || centerprint_title_left != "") {
@@ -363,7 +419,7 @@ void HUD_CenterPrint()
 
                if (time < centerprint_start_time[j]) continue;
 
-               float fade_in_time = autocvar_hud_panel_centerprint_fade_in;
+               float fade_in_time = 0;
                float fade_out_time = autocvar_hud_panel_centerprint_fade_out;
 
                if (centerprint_countdown_num[j] && centerprint_start_time[j]) {
@@ -397,7 +453,8 @@ void HUD_CenterPrint()
                a *= panel_fg_alpha;
 
                // finally set the size based on the alpha
-               sz = autocvar_hud_panel_centerprint_fade_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_minfontsize);
+               //sz = autocvar_hud_panel_centerprint_fade_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_minfontsize);
+               sz = 1; // remove zoom;
                drawfontscale = hud_scale * sz;
 
                if (centerprint_countdown_num[j])
index 98f268b3456570268cde81205dc700b609d58ca2..fca94c89c8e9ea6565840df414fdee58fda9c202 100644 (file)
@@ -3,14 +3,14 @@
 
 bool autocvar_hud_panel_centerprint;
 float autocvar_hud_panel_centerprint_align;
-float autocvar_hud_panel_centerprint_fade_in = 0.15;
+//float autocvar_hud_panel_centerprint_fade_in = 0;
 float autocvar_hud_panel_centerprint_fade_out = 0.15;
 float autocvar_hud_panel_centerprint_fade_subsequent = 1;
 float autocvar_hud_panel_centerprint_fade_subsequent_passone = 3;
 float autocvar_hud_panel_centerprint_fade_subsequent_passone_minalpha = 0.5;
 float autocvar_hud_panel_centerprint_fade_subsequent_passtwo = 10;
 float autocvar_hud_panel_centerprint_fade_subsequent_passtwo_minalpha = 0.5;
-float autocvar_hud_panel_centerprint_fade_minfontsize = 1;
+//float autocvar_hud_panel_centerprint_fade_minfontsize = 1;
 bool autocvar_hud_panel_centerprint_flip;
 float autocvar_hud_panel_centerprint_fontscale = 1;
 float autocvar_hud_panel_centerprint_fontscale_bold = 1.4;
@@ -18,6 +18,9 @@ float autocvar_hud_panel_centerprint_fontscale_title = 1.8;
 bool autocvar_hud_panel_centerprint_dynamichud = true;
 float autocvar_hud_panel_centerprint_time;
 
+bool autocvar_hud_panel_centerprint_medals = true;
+int autocvar_hud_panel_centerprint_medals_max = 5;
+
 void centerprint_Add(int new_id, string strMessage, float duration, int countdown_num);
 void centerprint_AddStandard(string strMessage);
 void centerprint_Kill(int id);
@@ -26,3 +29,4 @@ void centerprint_KillAll();
 void centerprint_SetDuelTitle(string left, string right);
 void centerprint_SetTitle(string title);
 void centerprint_ClearTitle();
+void centerprint_Medal(string icon, int times);
index 448b9f408f954e2766762a28c0fff2e57ac8f478..d344b33ab369984a58a33a1998e5b4e01655a330 100644 (file)
@@ -1,6 +1,8 @@
 #include "chat.qh"
 
 #include <client/draw.qh>
+#include <common/items/inventory.qh>
+
 
 // Chat (#12)
 
@@ -157,6 +159,7 @@ void HUD_Chat()
        if (autocvar_con_chat != floor(mySize.y / autocvar_con_chatsize - 0.5))
                cvar_set("con_chat", ftos(floor(mySize.y / autocvar_con_chatsize - 0.5)));
 
+       //vector chatsize = '1 1 0' * autocvar_con_chatsize;
        if(autocvar__hud_configure)
        {
                vector chatsize = '1 1 0' * autocvar_con_chatsize;
index f84a3733027ca22cebc904f0926749fef1a4d04e..e5320ebbda5fbcc4a9ac395490080de965d8fdcb 100644 (file)
@@ -22,7 +22,7 @@ void HUD_HealthArmor_Export(int fh)
 
 void HUD_HealthArmor()
 {
-       int armor, health, fuel, air_time;
+       int armor, health, health_real, fuel, air_time;
        if(!autocvar__hud_configure)
        {
                if((!autocvar_hud_panel_healtharmor) || (spectatee_status == -1))
@@ -30,8 +30,10 @@ void HUD_HealthArmor()
                if(hud != HUD_NORMAL) return;
 
                health = STAT(HEALTH);
+               health_real = health;
                if(health <= 0)
                {
+                       health_real = max(health, -999);
                        health = 0;
                        prev_health = -1;
                        if(autocvar_hud_panel_healtharmor_hide_ondeath)
@@ -70,6 +72,7 @@ void HUD_HealthArmor()
        else
        {
                health = 150;
+               health_real = 150;
                armor = 75;
                fuel = 20;
                air_time = 6;
@@ -246,7 +249,7 @@ void HUD_HealthArmor()
                                HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, p_health/maxhealth, is_vertical, health_baralign, autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * pain_health_alpha, DRAWFLAG_NORMAL);
                        }
                        if(autocvar_hud_panel_healtharmor_text)
-                               DrawNumIcon(pos + health_offset, mySize, health, "health", is_vertical, false, health_iconalign, HUD_Get_Num_Color(health, maxhealth, true), 1);
+                               DrawNumIcon(pos + health_offset, mySize, health_real, "health", is_vertical, false, health_iconalign, HUD_Get_Num_Color(health, maxhealth, true), 1);
                }
 
                //if(armor)
index 94bfa47511a9d7ece3909eb565b66e86a3758852..5342c77c1339b2c4f83d7261fc597f217ee87921 100644 (file)
@@ -11,7 +11,7 @@ void HUD_InfoMessages_Export(int fh)
        HUD_Write_Cvar("hud_panel_infomessages_flip");
 }
 
-float autocvar_hud_panel_infomessages_group0 = 1;
+//float autocvar_hud_panel_infomessages_group0 = 1;
 float autocvar_hud_panel_infomessages_group_fadetime = 0.4;
 float autocvar_hud_panel_infomessages_group_time = 6;
 const int IMG_COUNT = 1; // number of InfoMessage Groups
@@ -88,13 +88,16 @@ void HUD_InfoMessages()
        {
                if(spectatee_status)
                {
-                       if(spectatee_status == -1)
-                               s = _("^1Observing");
-                       else
-                               s = sprintf(_("^1Spectating: ^7%s"), entcs_GetName(current_player));
-                       InfoMessage(s);
+                       // z411 : Show the observed played if we have the spectator HUD disabled
+                       if(!autocvar_hud_panel_spect_playername) {
+                               if(spectatee_status == -1)
+                                       s = _("^1Observing");
+                               else
+                                       s = sprintf(_("^1Spectating: ^7%s"), entcs_GetName(current_player));
+                               InfoMessage(s);
+                       }
 
-                       if(autocvar_hud_panel_infomessages_group0)
+                       /*if(autocvar_hud_panel_infomessages_group0)
                        {
                                img_curr_group = 0;
                                switch(img_select(img_curr_group) % 3)
@@ -119,17 +122,20 @@ void HUD_InfoMessages()
                                                break;
                                }
                                InfoMessage(s);
-                       }
+                       }*/
 
-                       bool mutator_returnvalue = MUTATOR_CALLHOOK(DrawInfoMessages, pos, mySize, img_curr_group);
-                       pos = M_ARGV(0, vector);
-                       img_curr_group = M_ARGV(2, int);
+                       //bool mutator_returnvalue = MUTATOR_CALLHOOK(DrawInfoMessages, pos, mySize, img_curr_group);
+                       //pos = M_ARGV(0, vector);
+                       //img_curr_group = M_ARGV(2, int);
 
-                       if(!mutator_returnvalue)
+                       if(entcs_GetWantsJoin(current_player))
                        {
-                               s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey(_("jump"), "+jump"));
-                               InfoMessage(s);
+                               int tm = Team_IndexToTeam(entcs_GetWantsJoin(current_player));
+                               s = sprintf(_("^2You're queued to join the %s%s^2 team"), Team_ColorCode(tm), Team_ColorName(tm));
                        }
+                       else
+                               s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey(_("jump"), "+jump"));
+                       InfoMessage(s);
                }
 
                if (time < STAT(GAMESTARTTIME))
@@ -223,6 +229,12 @@ void HUD_InfoMessages()
                                InfoMessage(s);
                        }
                }
+
+               // z411
+               if (motd_permanent != "")
+                       InfoMessage(motd_permanent);
+               
+               MUTATOR_CALLHOOK(DrawInfoMessages, pos, mySize, img_curr_group);
        }
        else
        {
index fdaf50de2270005b2bede8b151015947dc7c7e33..eea4930de9dc4b2c6ee3d96baf8ba22b33700988 100644 (file)
@@ -30,7 +30,7 @@ void HUD_ModIcons()
                if(!autocvar_hud_panel_modicons) return;
                if(!HUD_ModIcons_GameType) return;
        }
-
+       
        if(mod_active || autocvar__hud_configure)
                mod_alpha = min(mod_alpha + frametime * 2, 1);
        else
index 0f3425203600cb5be5fedaedb0b45d9bcb32b9af..435ebc537588e9c3e52e3d6907b3feda9252ae75 100644 (file)
@@ -102,10 +102,13 @@ bool QuickMenu_Open(string mode, string submenu, string file)
 
        if(mode == "")
        {
-               if(file == "" || file == "0")
-                       mode = "default";
-               else
+               if(autocvar__hud_panel_quickmenu_file_from_server)
+               {
                        mode = "file";
+                       file = autocvar__hud_panel_quickmenu_file_from_server;
+               }
+               else
+                       mode = "default";
        }
 
        if(mode == "default")
index c33fce08b16a1ae80a9d3a256e99551ea7424167..a96da350183f182c16c91fa84d14f290cc18f3cd 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <client/draw.qh>
 #include <client/hud/panel/scoreboard.qh>
+#include <common/mapinfo.qh>
 #include <common/ent_cs.qh>
 #include <common/scores.qh>
 
@@ -14,7 +15,7 @@ void HUD_Score_Export(int fh)
 }
 
 void HUD_Score_Rankings(vector pos, vector mySize, entity me)
-{
+{      
        float score;
        entity tm = NULL, pl;
        int SCOREPANEL_MAX_ENTRIES = 6;
@@ -77,7 +78,7 @@ void HUD_Score_Rankings(vector pos, vector mySize, entity me)
                return;
        }
 
-       Scoreboard_UpdatePlayerTeams();
+       /*
        if (team_count)
        {
                // show team scores in the first line
@@ -96,45 +97,110 @@ void HUD_Score_Rankings(vector pos, vector mySize, entity me)
                first_pl = 1;
                pos.y += fontsize.y;
                tm = teams.sort_next;
-       }
-       i = first_pl;
+       }*/
 
-       do
-       for (pl = players.sort_next; pl && i<entries; pl = pl.sort_next)
+       // z411 Basic team stats
+       if (team_count)
        {
-               if ((team_count && pl.team != tm.team) || pl.team == NUM_SPECTATOR)
-                       continue;
-
-               if (i == entries-1 && !me_printed && pl != me)
-               if (autocvar_hud_panel_score_rankings == 1 && spectatee_status != -1)
-               {
-                       for (pl = me.sort_next; pl; pl = pl.sort_next)
-                               if (pl.team != NUM_SPECTATOR)
-                                       break;
+               i = 0;
+               for(tm = teams.sort_next; tm; tm = tm.sort_next) {
+                       if(tm.team == NUM_SPECTATOR)
+                               continue;
+                       if(!tm.team)
+                               continue;
 
-                       if (pl)
-                               rgb = '1 1 0'; //not last but not among the leading players: yellow
-                       else
-                               rgb = '1 0 0'; //last: red
-                       pl = me;
+                       /*if (tm.team == myteam)
+                               drawfill(pos + eX * score_size * i, vec2(score_size, fontsize.y), '1 1 1', highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores(ts_primary))), vec2(score_size, fontsize.y), Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       ++i;*/
+                       
+                       if (tm.team == myteam)
+                       {
+                               if (i == 0)
+                                       rgb = '0 1 0'; //first: green
+                               me_printed = true;
+                               drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                       }
+                       
+                       score_color = Team_ColorRGB(tm.team) * 0.8;
+                       
+                       // TODO secondary scores test, remove
+                       if(gametype.m_modscores)
+                       {
+                               string icon;
+                               if(tm.team == NUM_TEAM_1)
+                                       icon = "gfx/hud/luma/player_red";
+                               else if(tm.team == NUM_TEAM_2)
+                                       icon = "gfx/hud/luma/player_blue";
+                               else
+                                       icon = "gfx/hud/luma/player_neutral";
+                               
+                               vector icon_sz = draw_getimagesize(icon);
+                               vector icon_sz_new = vec2(fontsize.y*(icon_sz.x/icon_sz.y), fontsize.y);
+                               
+                               s = ftos(gametype.m_modscores(tm.team));
+                               float s_width = stringwidth(s, false, fontsize) + icon_sz_new.x;
+                               
+                               //drawfill(pos, eX * s_width + eY * fontsize.y, score_color, panel_fg_alpha * 0.3, DRAWFLAG_NORMAL);
+                               drawpic(pos, icon, icon_sz_new, '1 1 1', panel_fg_alpha * 0.7, DRAWFLAG_NORMAL);
+                               drawstring(pos + eX * icon_sz_new.x, s, fontsize, '1 1 1', panel_fg_alpha * 0.7, DRAWFLAG_NORMAL);
+                               
+                               s = textShortenToWidth(Team_CustomName(tm.team), name_size - s_width, fontsize, stringwidth_colors);
+                       } else
+                               s = textShortenToWidth(Team_CustomName(tm.team), name_size, fontsize, stringwidth_colors);
+                       // TODO end
+                       
+                       drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       
+                       draw_beginBoldFont();
+                       drawstring(pos + eX * (name_size + spacing_size), ftos(tm.(teamscores(ts_primary))), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       draw_endBoldFont();
+                       
+                       pos.y += fontsize.y;
+                       ++i;
                }
-
-               if (pl == me)
+       } else {
+               i = first_pl;
+               
+               do
+               for (pl = players.sort_next; pl && i<entries; pl = pl.sort_next)
                {
-                       if (i == first_pl)
-                               rgb = '0 1 0'; //first: green
-                       me_printed = true;
-                       drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                       if ((team_count && pl.team != tm.team) || pl.team == NUM_SPECTATOR)
+                               continue;
+
+                       if (i == entries-1 && !me_printed && pl != me)
+                       if (autocvar_hud_panel_score_rankings == 1 && spectatee_status != -1)
+                       {
+                               for (pl = me.sort_next; pl; pl = pl.sort_next)
+                                       if (pl.team != NUM_SPECTATOR)
+                                               break;
+
+                               if (pl)
+                                       rgb = '1 1 0'; //not last but not among the leading players: yellow
+                               else
+                                       rgb = '1 0 0'; //last: red
+                               pl = me;
+                       }
+               
+                       if (team_count)
+                               score_color = Team_ColorRGB(pl.team) * 0.8;
+                       
+                       if (pl == me)
+                       {
+                               if (i == first_pl)
+                                       rgb = '0 1 0'; //first: green
+                               me_printed = true;
+                               drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                       }
+                       
+                       s = textShortenToWidth(entcs_GetName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
+                       drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores(ps_primary))), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       pos.y += fontsize.y;
+                       ++i;
                }
-               if (team_count)
-                       score_color = Team_ColorRGB(pl.team) * 0.8;
-               s = textShortenToWidth(entcs_GetName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
-               drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores(ps_primary))), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
-               pos.y += fontsize.y;
-               ++i;
+               while (i<entries && team_count && (tm = tm.sort_next) && (tm.team != NUM_SPECTATOR || (tm = tm.sort_next)));
        }
-       while (i<entries && team_count && (tm = tm.sort_next) && (tm.team != NUM_SPECTATOR || (tm = tm.sort_next)));
 }
 
 void HUD_Score()
@@ -144,6 +210,11 @@ void HUD_Score()
                if(!autocvar_hud_panel_score) return;
                if(MUTATOR_CALLHOOK(HUD_Score_show)) return;
        }
+       
+       Scoreboard_UpdatePlayerTeams();
+       
+       // z411 : Don't display if we have the spectator HUD scores enabled
+       if(spectatee_status && autocvar_hud_panel_spect_scores) return;
 
        HUD_Panel_LoadCvars();
        vector pos, mySize;
index 35227ffab524c63bb077dfb624b4005f19ed4032..92e0f4ed0d51935374314977255453640bf6f134 100644 (file)
@@ -9,6 +9,7 @@
 #include <common/constants.qh>
 #include <common/ent_cs.qh>
 #include <common/mapinfo.qh>
+#include <common/gamemodes/gamemode/duel/duel.qh>
 #include <common/minigames/cl_minigames.qh>
 #include <common/net_linked.qh>
 #include <common/scores.qh>
@@ -49,6 +50,16 @@ string autocvar_hud_fontsize;
 string hud_fontsize_str;
 float max_namesize;
 
+vector duel_score_fontsize;
+vector duel_name_fontsize;
+vector duel_score_size;
+vector team_score_fontsize;
+vector team_name_fontsize;
+vector team_score_size;
+int total_medals;
+
+float autocvar_hud_panel_scoreboard_duel_weapon_scale = 1.25; // z411
+
 float sbt_bg_alpha;
 float sbt_fg_alpha;
 float sbt_fg_alpha_self;
@@ -108,6 +119,9 @@ string autocvar_hud_panel_scoreboard_playerid_prefix = "#";
 string autocvar_hud_panel_scoreboard_playerid_suffix = " ";
 bool autocvar_hud_panel_scoreboard_scores_per_round;
 
+int average_ping[NUM_TEAMS];
+int total_weapons;
+
 float scoreboard_time;
 
 SHUTDOWN(scoreboard)
@@ -135,6 +149,7 @@ string Label_getInfo(string label, int mode)
                SCO_LABEL(_("SCO^bctime"),        "bctime", "             ", _("Total amount of time holding the ball in Keepaway"));
                SCO_LABEL(_("SCO^caps"),          "caps", "               ", _("How often a flag (CTF) or a key (KeyHunt) was captured"));
                SCO_LABEL(_("SCO^captime"),       "captime", "            ", _("Time of fastest capture (CTF)"));
+               SCO_LABEL(_("SCO^cn"),            "cn", "                 ", _("Country of player"));
                SCO_LABEL(_("SCO^deaths"),        "deaths", "             ", _("Number of deaths"));
                SCO_LABEL(_("SCO^destroyed"),     "destroyed", "          ", _("Number of keys destroyed by pushing them into void"));
                SCO_LABEL(_("SCO^damage"),        "dmg", "                ", _("The total damage done"));
@@ -740,7 +755,7 @@ void Cmd_Scoreboard_Help()
 // otherwise the previous exclusive rule warns anyway
 // e.g. -teams,rc,cts,lms/kills ?+rc/kills
 #define SCOREBOARD_DEFAULT_COLUMNS \
-"ping pl fps name |" \
+"ping pl fps cn name |" \
 " -teams,rc,cts,surv,inv,lms/kills +ft,tdm,tmayhem/kills ?+rc,inv/kills" \
 " -teams,surv,lms/deaths +ft,tdm,tmayhem/deaths" \
 " +tdm/sum" \
@@ -791,7 +806,7 @@ void Cmd_Scoreboard_SetFields(int argc)
                }
                else if(argv(2) == "all" || argv(2) == "ALL")
                {
-                       string s = "ping pl name |"; // scores without label (not really scores)
+                       string s = "ping pl cn name |"; // scores without label (not really scores)
                        if(argv(2) == "ALL")
                        {
                                // scores without label
@@ -816,6 +831,14 @@ void Cmd_Scoreboard_SetFields(int argc)
        sbt_num_fields = 0;
 
        hud_fontsize = HUD_GetFontsize("hud_fontsize");
+       
+       duel_score_fontsize = hud_fontsize * 3;
+       duel_name_fontsize = hud_fontsize * 1.5;
+       duel_score_size = vec2(duel_score_fontsize.x * 1.5, duel_score_fontsize.y * 1.25);
+       
+       team_score_fontsize = hud_fontsize * 2;
+       team_name_fontsize = hud_fontsize * 1.5;
+       team_score_size = vec2(team_score_fontsize.x * 1.5, team_score_fontsize.y * 1.25);
 
        for(i = 1; i < argc - 1; ++i)
        {
@@ -847,10 +870,12 @@ void Cmd_Scoreboard_SetFields(int argc)
                        // fields without a label (not networked via the score system)
                        case "ping": sbt_field[sbt_num_fields] = SP_PING; break;
                        case "pl": sbt_field[sbt_num_fields] = SP_PL; break;
+                       case "cn": sbt_field[sbt_num_fields] = SP_COUNTRY; break; //LegendGuard adds cn label for Country column 05-04-2021
                        case "name": case "nick": sbt_field[sbt_num_fields] = SP_NAME; have_name = true; break;
                        case "|": sbt_field[sbt_num_fields] = SP_SEPARATOR; have_separator = true; break;
                        case "kd": case "kdr": case "kdratio": sbt_field[sbt_num_fields] = SP_KDRATIO; break;
                        case "sum": case "diff": case "k-d": sbt_field[sbt_num_fields] = SP_SUM; break;
+                       case "cn": sbt_field[sbt_num_fields] = SP_COUNTRY; break; //LegendGuard adds cn label for Country column 05-04-2021
                        case "frags": sbt_field[sbt_num_fields] = SP_FRAGS; break;
                        default: // fields with a label
                        {
@@ -968,6 +993,7 @@ vector sbt_field_rgb;
 string sbt_field_icon0;
 string sbt_field_icon1;
 string sbt_field_icon2;
+string sbt_field_icon3; //LegendGuard adds for Country player flags 05-04-2021
 vector sbt_field_icon0_rgb;
 vector sbt_field_icon1_rgb;
 vector sbt_field_icon2_rgb;
@@ -994,7 +1020,22 @@ string Scoreboard_GetName(entity pl)
                        sbt_field_icon2_rgb = colormapPaletteColor(f % 16, 1);
                }
        }
-       return entcs_GetName(pl.sv_entnum);
+       if(entcs_GetRank(pl.sv_entnum) != "")
+               return strcat(entcs_GetRank(pl.sv_entnum), "^7 ", entcs_GetName(pl.sv_entnum));
+       else
+               return entcs_GetName(pl.sv_entnum);
+}
+
+//LegendGuard adds GetCountrycode function 05-04-2021
+string Scoreboard_GetCountrycode(entity pl)
+{
+       int ccode = entcs_GetCountryCode(pl.sv_entnum);
+       if(ccode)
+               sbt_field_icon3 = strcat("gfx/flags/", ftos(ccode));
+       else
+               sbt_field_icon3 = strcat("gfx/flags/", ftos(0)); //if user hasn't assigned country flag
+       
+       return "";
 }
 
 int autocvar_hud_panel_scoreboard_ping_best = 0;
@@ -1013,6 +1054,21 @@ vector autocvar_hud_panel_scoreboard_ping_worst_color = '1 0 0';
 #define COLOR_MED autocvar_hud_panel_scoreboard_ping_medium_color
 #define COLOR_HIGH autocvar_hud_panel_scoreboard_ping_high_color
 #define COLOR_WORST autocvar_hud_panel_scoreboard_ping_worst_color
+
+vector getPingColor(float f)
+{
+       if(f < PING_BEST)
+               return COLOR_BEST;
+       else if(f < PING_MED)
+               return COLOR_BEST + (COLOR_MED - COLOR_BEST) * ((f - PING_BEST) / (PING_MED - PING_BEST));
+       else if(f < PING_HIGH)
+               return COLOR_MED + (COLOR_HIGH - COLOR_MED) * ((f - PING_MED) / (PING_HIGH - PING_MED));
+       else if(f < PING_WORST)
+               return COLOR_HIGH + (COLOR_WORST - COLOR_HIGH) * ((f - PING_HIGH) / (PING_WORST - PING_HIGH));
+       else
+               return COLOR_WORST;
+}
+
 string Scoreboard_GetField(entity pl, PlayerScoreField field, bool per_round)
 {
        float tmp, num, denom;
@@ -1022,6 +1078,7 @@ string Scoreboard_GetField(entity pl, PlayerScoreField field, bool per_round)
        sbt_field_icon0 = "";
        sbt_field_icon1 = "";
        sbt_field_icon2 = "";
+       sbt_field_icon3 = ""; //LegendGuard adds for Country column 05-04-2021
        sbt_field_icon0_rgb = '1 1 1';
        sbt_field_icon1_rgb = '1 1 1';
        sbt_field_icon2_rgb = '1 1 1';
@@ -1037,16 +1094,7 @@ string Scoreboard_GetField(entity pl, PlayerScoreField field, bool per_round)
                        f = pl.ping;
                        if(f == 0)
                                return _("N/A");
-                       if(f < PING_BEST)
-                               sbt_field_rgb = COLOR_BEST;
-                       else if(f < PING_MED)
-                               sbt_field_rgb = COLOR_BEST + (COLOR_MED - COLOR_BEST) * ((f - PING_BEST) / (PING_MED - PING_BEST));
-                       else if(f < PING_HIGH)
-                               sbt_field_rgb = COLOR_MED + (COLOR_HIGH - COLOR_MED) * ((f - PING_MED) / (PING_HIGH - PING_MED));
-                       else if(f < PING_WORST)
-                               sbt_field_rgb = COLOR_HIGH + (COLOR_WORST - COLOR_HIGH) * ((f - PING_HIGH) / (PING_WORST - PING_HIGH));
-                       else
-                               sbt_field_rgb = COLOR_WORST;
+                       sbt_field_rgb = getPingColor(f);
                        return ftos(f);
 
                case SP_PL:
@@ -1062,6 +1110,16 @@ string Scoreboard_GetField(entity pl, PlayerScoreField field, bool per_round)
                        tmp = bound(0, f / 0.2 + tmp / 0.04, 1); // 20% is REALLY BAD pl
                        sbt_field_rgb = '1 0.5 0.5' - '0 0.5 0.5' * tmp;
                        return str;
+               
+               //LegendGuard adds Country REGISTER in the switch 05-04-2021
+               case SP_COUNTRY:
+                       str = Scoreboard_GetCountrycode(pl);
+                       return str;
+
+               //LegendGuard adds Country REGISTER in the switch 05-04-2021
+               case SP_COUNTRY:
+                       str = Scoreboard_GetCountrycode(pl);
+                       return str;
 
                case SP_NAME:
                        str = Scoreboard_GetName(pl);
@@ -1134,6 +1192,7 @@ string Scoreboard_GetField(entity pl, PlayerScoreField field, bool per_round)
                                sbt_field_rgb = '1 1 1';
                                return ((pl.ping == 0) ? _("N/A") : "..."); // if 0 ping, either connecting or bot (either case can't show proper score)
                        }
+
                        //sbt_field_rgb = HUD_Get_Num_Color(fps, 200, true);
                        sbt_field_rgb = '1 0 0' + '0 1 1' * (bound(0, fps, 60) / 60);
                        return ftos(fps);
@@ -1197,6 +1256,15 @@ string Scoreboard_FixColumnWidth(int i, string str)
                        sbt_fixcolumnwidth_iconlen = f;
        }
 
+       //LegendGuard adds conditional for Country column 05-04-2021
+       if(sbt_field_icon3 != "")
+       {
+               sz = draw_getimagesize(sbt_field_icon3);
+               f = sz.x / sz.y;
+               if(sbt_fixcolumnwidth_iconlen < f)
+                       sbt_fixcolumnwidth_iconlen = f;
+       }
+
        if(sbt_fixcolumnwidth_iconlen != 0)
        {
                sbt_fixcolumnwidth_iconlen *= hud_fontsize.y / hud_fontsize.x; // fix icon aspect
@@ -1242,10 +1310,13 @@ void Scoreboard_initFieldSizes()
        }
 }
 
-vector Scoreboard_DrawHeader(vector pos, vector rgb, bool other_players)
+vector Scoreboard_DrawHeader(vector pos, vector rgb, bool other_players, int team)
 {
        int i;
+       string title_str;
+       vector title_rgb;
        vector column_dim = eY * panel_size.y;
+       
        if(other_players)
                column_dim.y -= 1.25 * hud_fontsize.y;
        vector text_offset = eY * (1.25 - 1) / 2 * hud_fontsize.y;
@@ -1254,11 +1325,23 @@ vector Scoreboard_DrawHeader(vector pos, vector rgb, bool other_players)
        {
                if(sbt_field[i] == SP_SEPARATOR)
                        break;
+               
+               vector text_offset_center = '0 0 0';
+               
+               if(sbt_field[i] == SP_PING && teamplay) {
+                       title_str = sprintf("(%d)", average_ping[Team_TeamToIndex(team) - 1]);
+                       title_rgb = getPingColor(average_ping[Team_TeamToIndex(team) - 1]);
+                       text_offset_center.x = sbt_field_size[i] - stringwidth(title_str, false, hud_fontsize);
+               } else {
+                       title_str = sbt_field_title[i];
+                       title_rgb = rgb * 1.5;
+               }
+               
                column_dim.x = sbt_field_size[i] + hud_fontsize.x;
                if (sbt_highlight)
                        if (i % 2)
                                drawfill(pos - eX * hud_fontsize.x * 0.5, column_dim, '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
-               drawstring(pos + text_offset, sbt_field_title[i], hud_fontsize, rgb * 1.5, sbt_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring(pos + text_offset + text_offset_center, title_str, hud_fontsize, title_rgb, sbt_fg_alpha, DRAWFLAG_NORMAL);
                pos.x += column_dim.x;
        }
        if(sbt_field[i] == SP_SEPARATOR)
@@ -1350,6 +1433,8 @@ void Scoreboard_DrawItem(vector item_pos, vector rgb, entity pl, bool is_self, i
                        drawpic(pos - tmp, sbt_field_icon1, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon1_rgb, fg_alpha, DRAWFLAG_NORMAL);
                if(sbt_field_icon2 != "")
                        drawpic(pos - tmp, sbt_field_icon2, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon2_rgb, fg_alpha, DRAWFLAG_NORMAL);
+               if(sbt_field_icon3 != "") //LegendGuard adds conditional for Country column 05-04-2021
+                       drawpic(pos - tmp, sbt_field_icon3, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon1_rgb, fg_alpha, DRAWFLAG_NORMAL);
        }
 
        if(sbt_field[i] == SP_SEPARATOR)
@@ -1384,6 +1469,8 @@ void Scoreboard_DrawItem(vector item_pos, vector rgb, entity pl, bool is_self, i
                                drawpic(pos - tmp, sbt_field_icon1, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon1_rgb, fg_alpha, DRAWFLAG_NORMAL);
                        if(sbt_field_icon2 != "")
                                drawpic(pos - tmp, sbt_field_icon2, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon2_rgb, fg_alpha, DRAWFLAG_NORMAL);
+                       if(sbt_field_icon3 != "") //LegendGuard adds conditional for Country column 05-04-2021
+                               drawpic(pos - tmp, sbt_field_icon3, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon1_rgb, fg_alpha, DRAWFLAG_NORMAL);
                        pos.x -= sbt_field_size[i] + hud_fontsize.x;
                }
        }
@@ -1397,6 +1484,7 @@ vector Scoreboard_DrawOthers(vector item_pos, vector rgb, int this_team, entity
        int i = 0;
        vector h_pos = item_pos;
        vector h_size = vec2(panel_size.x, hud_fontsize.y * 1.25);
+       vector sz;
 
        bool complete = (this_team == NUM_SPECTATOR);
 
@@ -1430,6 +1518,25 @@ vector Scoreboard_DrawOthers(vector item_pos, vector rgb, int this_team, entity
                        continue;
                if(pl == ignored_pl)
                        continue;
+               
+               string flag_name = "";
+               vector flag_size = '0 0 0';
+               Scoreboard_GetField(pl, SP_COUNTRY, autocvar_hud_panel_scoreboard_scores_per_round);
+               
+               if(sbt_field_icon3 != "") {
+                       sz = draw_getimagesize(sbt_field_icon3);
+                       flag_name = sbt_field_icon3;
+                       flag_size = vec2(hud_fontsize.x * (sz.x / sz.y), hud_fontsize.y);
+               }
+               
+               if(entcs_GetWantsJoin(pl.sv_entnum))
+               {
+                       vector tmcolor = Team_ColorRGB(Team_IndexToTeam(entcs_GetWantsJoin(pl.sv_entnum)));
+                       tmcolor -= tmcolor * sin(2*M_PI*time);
+
+                       drawstring(pos, "(Q)", hud_fontsize, tmcolor, sbt_fg_alpha, DRAWFLAG_NORMAL);
+                       pos.x += stringwidth("(Q) ", true, hud_fontsize);
+               }
 
                field = "";
                if(this_team == NUM_SPECTATOR)
@@ -1440,7 +1547,11 @@ vector Scoreboard_DrawOthers(vector item_pos, vector rgb, int this_team, entity
                else if(autocvar_hud_panel_scoreboard_others_showscore)
                        field = Scoreboard_GetField(pl, SP_SCORE, autocvar_hud_panel_scoreboard_scores_per_round);
 
-               string str = entcs_GetName(pl.sv_entnum);
+               string str;
+               if(entcs_GetRank(pl.sv_entnum) != "")
+                       str = strcat(entcs_GetRank(pl.sv_entnum), "^7 ", entcs_GetName(pl.sv_entnum));
+               else
+                       str = entcs_GetName(pl.sv_entnum);
                if (autocvar_hud_panel_scoreboard_playerid)
                        str = Scoreboard_AddPlayerId(str, pl);
                str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors);
@@ -1472,6 +1583,11 @@ vector Scoreboard_DrawOthers(vector item_pos, vector rgb, int this_team, entity
                        }
                }
 
+               if(flag_name != "") {
+                       drawpic(pos, flag_name, flag_size, sbt_field_icon1_rgb, sbt_fg_alpha, DRAWFLAG_NORMAL);
+                       pos.x += flag_size.x + hud_fontsize.x * 0.5;
+               }
+
                if (scoreboard_selected_panel == SB_PANEL_SCOREBOARD && scoreboard_ui_enabled == 1)
                {
                        if (pl == scoreboard_selected_player)
@@ -1485,6 +1601,7 @@ vector Scoreboard_DrawOthers(vector item_pos, vector rgb, int this_team, entity
                vector name_pos = pos;
                if((this_team == NUM_SPECTATOR) && autocvar_hud_panel_scoreboard_spectators_aligned)
                        name_pos.x += max(fieldsize, min_fieldsize) + 2 * fieldpadding + hud_fontsize.x * 0.25;
+
                drawcolorcodedstring(name_pos, str, hud_fontsize, sbt_fg_alpha, DRAWFLAG_NORMAL);
                if(field != "")
                {
@@ -1510,6 +1627,343 @@ vector Scoreboard_DrawOthers(vector item_pos, vector rgb, int this_team, entity
        return vec2(item_pos.x, item_pos.y + i * hud_fontsize.y * 1.25);
 }
 
+vector Scoreboard_DrawMedal(vector pos, string icon, float height, float number)
+{
+       if(!number) return pos;
+       total_medals += number;
+       
+       vector tmp_sz, tmp_sz2;
+       tmp_sz = draw_getimagesize(icon);
+       tmp_sz2 = vec2(height*(tmp_sz.x/tmp_sz.y), height);
+       string val = ftos(number);
+       
+       drawpic(pos, icon, tmp_sz2, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       
+       pos.x += tmp_sz2.x + hud_fontsize.x * 0.25;
+       drawstring(pos + eY * ((tmp_sz2.y - hud_fontsize.y) / 2), val, hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       
+       pos.x += stringwidth(val, false, hud_fontsize) + hud_fontsize.x * 0.5;
+       return pos;
+}
+
+vector Scoreboard_Duel_DrawPickup(vector pos, bool skinned, string icon, vector sz, float number, bool invert)
+{
+       vector tmp_in = pos;
+       vector tmp_sz, tmp_sz2;
+       string picpath;
+       
+       // Icon
+       if(skinned) {
+               picpath = strcat(hud_skin_path, "/", icon);
+               if(precache_pic(picpath) == "")
+                       picpath = strcat("gfx/hud/default/", icon);
+       } else {
+               picpath = icon;
+       }
+               
+       tmp_sz = draw_getimagesize(picpath);
+       tmp_sz2 = vec2(sz.y*(tmp_sz.x/tmp_sz.y), sz.y);
+       
+       tmp_in.x = pos.x + ((sz.x - tmp_sz2.x) / 2);
+       drawpic(tmp_in, picpath, tmp_sz2, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       
+       // Number
+       if(invert)
+               tmp_in.x += tmp_sz2.x + hud_fontsize.x * 0.25;
+       else
+               tmp_in.x -= hud_fontsize.x * 0.25 + hud_fontsize.x;
+       
+       tmp_in.y += (tmp_sz2.y - hud_fontsize.y) / 2;
+       drawstring(tmp_in,
+               ((number == -1) ? "?" : ftos(number)),
+               hud_fontsize, ((number > 0) ? '1 1 1' : '0.5 0.5 0.5'),
+               panel_fg_alpha,
+               DRAWFLAG_NORMAL);
+       
+       pos.y += sz.y * 1.1;
+       return pos;
+}
+
+int left_pl_dmg = 50;
+int right_pl_dmg = 50;
+void Scoreboard_Duel_DrawTable(vector pos, bool invert, entity pl, entity tm)
+{
+       vector tmp, tmp_in, tmp_sz, tmp_acc;
+       string tmp_str;
+       float sz;
+       float average_acc = 0;
+       
+       panel_pos = pos;
+       
+       HUD_Panel_DrawBg();
+       
+       // Stop here if there are no scores available
+       if(!pl) return;
+       if(entcs_GetSpecState(pl.sv_entnum) == ENTCS_SPEC_PURE) return;
+       
+       tmp = pos;
+       tmp.x += panel_bg_padding;
+       tmp.y += panel_bg_padding;
+       panel_size.x -= panel_bg_padding * 2;
+       
+       //if (sbt_bg_alpha)
+       //      drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", tmp, panel_size, rgb, sbt_bg_alpha, DRAWFLAG_NORMAL);
+
+       // Score: highlight
+       if(invert) { tmp.x += panel_size.x; tmp.x -= duel_score_size.x; }
+       drawfill(tmp, duel_score_size, '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
+       
+       // Score: text
+       tmp_str = ftos(pl.(scores(SP_SCORE)));
+       tmp_in = tmp;
+       tmp_in.x += (duel_score_size.x / 2) - (stringwidth(tmp_str, true, duel_score_fontsize) / 2);
+       tmp_in.y += (duel_score_size.y / 2) - (duel_score_fontsize.y / 2);
+       
+       draw_beginBoldFont();
+       drawstring(tmp_in, tmp_str, duel_score_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       draw_endBoldFont();
+       
+       tmp_in = tmp;
+       tmp_in.y += (duel_score_size.y - duel_name_fontsize.y) / 2;
+       
+       // RJZ rank
+       string rank_str = entcs_GetRank(pl.sv_entnum);
+       if(rank_str != "") {
+               if(invert)
+                       tmp_in.x -= stringwidth_colors(rank_str, duel_name_fontsize) + duel_name_fontsize.x * 0.5;
+               else
+                       tmp_in.x += duel_score_size.x + duel_name_fontsize.x * 0.5;
+               
+               draw_beginBoldFont();
+               drawcolorcodedstring(tmp_in, rank_str, duel_name_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+               draw_endBoldFont();
+       }
+       
+       // Player name
+       tmp_str = entcs_GetName(pl.sv_entnum);
+       if(invert)
+               tmp_in.x -= stringwidth_colors(tmp_str, duel_name_fontsize) + duel_name_fontsize.x * 0.5;
+       else
+               tmp_in.x += (rank_str != "" ? stringwidth_colors(rank_str, duel_name_fontsize) : duel_score_size.x) + duel_name_fontsize.x * 0.5;
+       drawcolorcodedstring(tmp_in, tmp_str, duel_name_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+       
+       //LegendGuard adds a conditional sentence for country column 05-04-2021
+       // Player country icon/flag
+       Scoreboard_GetField(pl, SP_COUNTRY, autocvar_hud_panel_scoreboard_scores_per_round);
+       if(sbt_field_icon3 != "") {
+               vector rsz = draw_getimagesize(sbt_field_icon3);
+               sbt_fixcolumnwidth_iconlen = rsz.x / rsz.y;
+               if(invert)
+                       tmp_in.x -= hud_fontsize.x * sbt_fixcolumnwidth_iconlen + duel_name_fontsize.x * 0.5;
+               else
+                       tmp_in.x += stringwidth_colors(tmp_str, duel_name_fontsize) + duel_name_fontsize.x * 0.5;
+               tmp_in.y += (duel_name_fontsize.y - hud_fontsize.y) / 2;
+               drawpic(tmp_in, sbt_field_icon3, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon1_rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+       }
+       
+       // Header
+       float column_width = panel_size.x / 5;
+       tmp.x = pos.x + panel_bg_padding;
+       tmp.y += hud_fontsize.y * 3 + hud_fontsize.y;
+       
+       vector column_dim;
+       int i;
+
+       i = (invert ? 4 : 0);
+       column_dim = vec2(column_width * 4, hud_fontsize.y);
+       
+       drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("kills", false, hud_fontsize) / 2),
+               "kills", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("dmg", false, hud_fontsize) / 2),
+               "dmg", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("acc", false, hud_fontsize) / 2),
+               "acc", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("hits", false, hud_fontsize) / 2),
+               "hits", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("ping", false, hud_fontsize) / 2),
+               "ping", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       
+       tmp.x = pos.x + panel_bg_padding;
+       tmp.y += hud_fontsize.y;
+       
+       // Main row
+       i = (invert ? 4 : 0);
+       
+       tmp_str = ftos(pl.(scores(SP_KILLS)));
+       drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth(tmp_str, false, hud_fontsize * 1.25) / 2),
+               tmp_str, hud_fontsize  * 1.25, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       
+       tmp_str = ftos(pl.(scores(SP_DMG)));
+       drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth(tmp_str, false, hud_fontsize * 1.25) / 2),
+               tmp_str, hud_fontsize  * 1.25, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       
+       tmp_acc = tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2);
+       
+       if(invert)
+               i--;
+       else
+               i++;
+       
+       tmp_str = Scoreboard_GetField(pl, SP_PING, autocvar_hud_panel_scoreboard_scores_per_round);
+       drawstring(tmp + eX * column_width * i + (eX * column_width / 2) - eX * (stringwidth(tmp_str, false, hud_fontsize * 1.25) / 2),
+               tmp_str, hud_fontsize * 1.25, sbt_field_rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+       tmp_str = Scoreboard_GetField(pl, SP_PL, autocvar_hud_panel_scoreboard_scores_per_round);
+       drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth(tmp_str, false, hud_fontsize * 0.75) / 2) + eY * (hud_fontsize.y * 1.25),
+               tmp_str, hud_fontsize * 0.75, sbt_field_rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+       tmp.x = pos.x + panel_bg_padding;
+       tmp.y += hud_fontsize.y * 2;
+       
+       tmp_in = tmp;
+       
+       // Accuracy rows
+       int dmg_percent;
+       vector dmg_color;
+       
+       total_weapons = 0;
+       int used_weapons = 0;
+       
+       WepSet weapons_inmap = WepSet_GetFromStat_InMap();
+       FOREACH(Weapons, it != WEP_Null, {
+               WepSet set = it.m_wepset;
+               if (!(weapons_inmap & set) && it != WEP_BLASTER && it != WEP_SHOTGUN) // z411 TODO : We'll be hardcoding this for now.
+                       continue;
+               if (it.spawnflags & WEP_TYPE_OTHER)
+                       continue;
+               
+               int weapon_cnt_fired = pl.accuracy_cnt_fired[i - WEP_FIRST];
+               int weapon_cnt_hit   = pl.accuracy_cnt_hit[i - WEP_FIRST];
+               int weapon_acc = 0;
+               if(weapon_cnt_fired)
+                       weapon_acc = floor((weapon_cnt_hit / weapon_cnt_fired) * 100);
+               average_acc += weapon_acc;
+               
+               // center vertically
+               vector row_in = tmp_in;
+               row_in.y += ((hud_fontsize.y * autocvar_hud_panel_scoreboard_duel_weapon_scale) - column_dim.y) / 2;
+               
+               // draw row background
+               drawfill(row_in + eX * column_width * (invert ? 1 : 0), column_dim, '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
+               
+               if(weapon_cnt_fired) {
+                       if(invert) {
+                               if(pl.accuracy_hit[i - WEP_FIRST] > left_pl_dmg)
+                                       left_pl_dmg = pl.accuracy_hit[i - WEP_FIRST];
+                               dmg_percent = pl.accuracy_hit[i - WEP_FIRST] / left_pl_dmg;
+                       } else {
+                               if(pl.accuracy_hit[i - WEP_FIRST] > right_pl_dmg)
+                                       right_pl_dmg = pl.accuracy_hit[i - WEP_FIRST];
+                               dmg_percent = pl.accuracy_hit[i - WEP_FIRST] / right_pl_dmg;
+                       }
+                       
+                       // convert percentage range to 0.4 - 1
+                       dmg_percent = dmg_percent * (1 - 0.4) + 0.4;
+                       
+                       dmg_color.x = dmg_percent;
+                       dmg_color.y = dmg_percent;
+                       dmg_color.z = dmg_percent;
+                       
+                       string draw_str;
+                       
+                       // weapon stats
+                       int c = (invert ? 4 : 0);
+                       
+                       draw_str = ftos(pl.accuracy_frags[i - WEP_FIRST]);
+                       drawstring(row_in + eX * column_width * (invert ? c-- : c++) + eX * ((column_width - stringwidth(draw_str, false, hud_fontsize)) / 2),
+                               draw_str, hud_fontsize, dmg_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       
+                       draw_str = ftos(pl.accuracy_hit[i - WEP_FIRST]);
+                       drawstring(row_in + eX * column_width * (invert ? c-- : c++) + eX * ((column_width - stringwidth(draw_str, false, hud_fontsize)) / 2),
+                               draw_str, hud_fontsize, dmg_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       
+                       draw_str = sprintf("%d%%", weapon_acc);
+                       drawstring(row_in + eX * column_width * (invert ? c-- : c++) + eX * ((column_width - stringwidth(draw_str, false, hud_fontsize)) / 2),
+                               draw_str, hud_fontsize, dmg_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       
+                       draw_str = strcat(ftos(weapon_cnt_hit), " / ", ftos(weapon_cnt_fired));
+                       drawstring(row_in + eX * column_width * (invert ? c-- : c++) + eX * (column_width / 2) - eX * stringwidth(ftos(weapon_cnt_hit), false, hud_fontsize) - eX * hud_fontsize.x * 0.5,
+                               draw_str, hud_fontsize, dmg_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+                       used_weapons++;
+               }
+               
+               // weapon icon
+               if(invert) {
+                       tmp_in.x = pos.x + panel_size.x - panel_bg_padding - hud_fontsize.x / 2;
+                       drawpic_aspect_skin(tmp_in, it.model2, vec2(50, hud_fontsize.y * autocvar_hud_panel_scoreboard_duel_weapon_scale), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               }
+               
+               tmp_in.x = pos.x + panel_bg_padding;
+               tmp_in.y += hud_fontsize.y * autocvar_hud_panel_scoreboard_duel_weapon_scale;
+               
+               total_weapons++;
+       });
+       
+       if(used_weapons)
+               average_acc = floor((average_acc / used_weapons) + 0.5);
+       
+       // draw total accuracy now
+       tmp_str = sprintf("%d%%", average_acc);
+       drawstring(tmp_acc - eX * (stringwidth(tmp_str, false, hud_fontsize * 1.25) / 2),
+               tmp_str, hud_fontsize * 1.25, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       
+       // Icon column
+       vector icon_sz = vec2(column_width, hud_fontsize.y*1.5);
+       
+       if(!invert)
+               tmp.x += column_width * 4;
+       // Medal rows
+       drawstring(tmp + eX * ((column_width - stringwidth("medals", false, hud_fontsize)) / 2),
+               "medals", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       tmp.y += hud_fontsize.y * 1.25;
+       
+       tmp = Scoreboard_Duel_DrawPickup(tmp, false, "gfx/medal/humiliation", icon_sz, pl.(scores(SP_MEDAL_HUMILIATION)), invert);
+       tmp = Scoreboard_Duel_DrawPickup(tmp, false, "gfx/medal/impressive", icon_sz, pl.(scores(SP_MEDAL_IMPRESSIVE)), invert);
+       tmp = Scoreboard_Duel_DrawPickup(tmp, false, "gfx/medal/excellent", icon_sz, pl.(scores(SP_MEDAL_EXCELLENT)), invert);
+       
+       // Item rows
+       drawstring(tmp + eX * ((column_width - stringwidth("items", false, hud_fontsize)) / 2),
+               "items", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       tmp.y += hud_fontsize.y * 1.25;
+       
+       float inv_num = -1;
+       FOREACH(Items,
+               it.m_id == ITEM_ArmorMega.m_id ||
+               it.m_id == ITEM_HealthMega.m_id ||
+               it.m_id == ITEM_ArmorBig.m_id, {
+               // If the match isn't over, Only show pickups if we're spectating or they're our own
+               if(intermission || warmup_stage || spectatee_status || pl.sv_entnum == current_player)
+                       inv_num = inventoryslots[pl.sv_entnum].inv_items[it.m_id];
+               tmp = Scoreboard_Duel_DrawPickup(tmp, true, it.m_icon, icon_sz, inv_num, invert);
+               
+               if(it.m_id == REGISTRY_MAX(Items))
+               break;
+       });
+}
+vector Scoreboard_MakeDuelTable(vector pos, entity tm, vector rgb, vector bg_size)
+{
+       vector end_pos = pos;
+       float screen_half = panel_size.x / 2;
+       float weapon_margin = hud_fontsize.x;
+       
+       panel_size.x = screen_half - weapon_margin;
+       if(total_weapons)
+               panel_size.y = max(duel_score_size.y * 5.5, duel_score_size.y * 2.25 + (hud_fontsize.y * autocvar_hud_panel_scoreboard_duel_weapon_scale * total_weapons));
+       else
+               panel_size.y = duel_score_size.y * 5.5;
+       
+       entity pl_left = players.sort_next;
+       entity pl_right = pl_left.sort_next;
+       
+       Scoreboard_Duel_DrawTable(pos, true, pl_left, tm);
+       Scoreboard_Duel_DrawTable(pos + eX * screen_half + eX * weapon_margin, false, pl_right, tm);
+       
+       end_pos.y += panel_size.y + (panel_bg_padding * 2);
+       panel_size.x = screen_half * 2;
+       return end_pos;
+}
+
 vector Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
 {
        int max_players = 999;
@@ -1570,12 +2024,14 @@ vector Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
 
 
        // print header row and highlight columns
-       pos = Scoreboard_DrawHeader(panel_pos, rgb, (max_players < tm.team_size));
+       pos = Scoreboard_DrawHeader(panel_pos, rgb, (max_players < tm.team_size), tm.team);
 
        // fill the table and draw the rows
        bool is_self = false;
        bool self_shown = false;
        int i = 0;
+       int with_ping = 0;
+       if(Team_IsValidTeam(tm.team)) average_ping[Team_TeamToIndex(tm.team) - 1] = 0;
        for(pl = players.sort_next; pl; pl = pl.sort_next)
        {
                if(pl.team != tm.team)
@@ -1597,11 +2053,17 @@ vector Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
                }
                is_self = (pl.sv_entnum == current_player);
                Scoreboard_DrawItem(pos, rgb, pl, is_self, i);
+               
+               if(Team_IsValidTeam(tm.team) && pl.ping) {
+                       average_ping[Team_TeamToIndex(tm.team) - 1] += pl.ping;
+                       ++with_ping;
+               }
                if(is_self)
                        self_shown = true;
                pos.y += 1.25 * hud_fontsize.y;
                ++i;
        }
+       if(with_ping) average_ping[Team_TeamToIndex(tm.team) - 1] /= with_ping;
 
        if (scoreboard_selected_panel == SB_PANEL_SCOREBOARD)
        {
@@ -1647,7 +2109,7 @@ bool Scoreboard_WouldDraw()
                return true;
        else if (intermission == 2)
                return false;
-       else if (spectatee_status != -1 && STAT(HEALTH) <= 0 && autocvar_cl_deathscoreboard && !MUTATOR_CALLHOOK(DrawDeathScoreboard)
+       else if (!spectatee_status && STAT(HEALTH) <= 0 && autocvar_cl_deathscoreboard && !MUTATOR_CALLHOOK(DrawDeathScoreboard)
                && (!HUD_MinigameMenu_IsOpened() || !active_minigame))
        {
                return true;
@@ -1657,6 +2119,49 @@ bool Scoreboard_WouldDraw()
        return false;
 }
 
+vector Scoreboard_MedalStats_Draw(vector pos)
+{
+       vector orig = pos;
+       float height = hud_fontsize.y * 2;
+       
+       entity pl = playerslots[current_player];
+       
+       vector title_pos = pos;
+       pos.x += 0.5 * hud_fontsize.x + panel_bg_padding;
+       pos.y += 1.25 * hud_fontsize.y;
+       
+       total_medals = 0;
+       
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/airshot",            height, pl.(scores(SP_MEDAL_AIRSHOT)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/damage",             height, pl.(scores(SP_MEDAL_DAMAGE)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/electrobitch",       height, pl.(scores(SP_MEDAL_ELECTROBITCH)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/excellent",          height, pl.(scores(SP_MEDAL_EXCELLENT)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/firstblood",         height, pl.(scores(SP_MEDAL_FIRSTBLOOD)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/headshot",           height, pl.(scores(SP_MEDAL_HEADSHOT)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/humiliation",        height, pl.(scores(SP_MEDAL_HUMILIATION)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/impressive",         height, pl.(scores(SP_MEDAL_IMPRESSIVE)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/yoda",                       height, pl.(scores(SP_MEDAL_YODA)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/telefrag",           height, pl.(scores(SP_MEDAL_TELEFRAG)));
+       
+       if(total_medals)
+               pos.x += hud_fontsize.x;
+       
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/accuracy",           height, pl.(scores(SP_MEDAL_ACCURACY)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/assist",             height, pl.(scores(SP_MEDAL_ASSIST)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/capture",            height, pl.(scores(SP_MEDAL_CAPTURE)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/defense",            height, pl.(scores(SP_MEDAL_DEFENSE)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/perfect",            height, pl.(scores(SP_MEDAL_PERFECT)));
+       
+       if(!total_medals) return orig;
+       
+       drawstring(title_pos, sprintf(_("Medal stats (total %d)"), total_medals),
+               hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       
+       pos.x = orig.x;
+       pos.y += height + hud_fontsize.y * 0.5;
+       return pos;
+}
+
 float average_accuracy;
 vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
 {
@@ -1831,6 +2336,7 @@ bool is_item_filtered(entity it)
 
 vector Scoreboard_ItemStats_Draw(vector pos, vector rgb, vector bg_size)
 {
+       Inventory g_inventory = inventoryslots[current_player];
        scoreboard_itemstats_fade_alpha = min(scoreboard_fade_alpha, scoreboard_itemstats_fade_alpha + frametime * 10);
 
        int disowned_cnt = 0;
@@ -1939,6 +2445,7 @@ vector MapStats_DrawKeyValue(vector pos, string key, string value) {
        return pos;
 }
 
+/*
 vector Scoreboard_MapStats_Draw(vector pos, vector rgb, vector bg_size) {
        float stat_secrets_found, stat_secrets_total;
        float stat_monsters_killed, stat_monsters_total;
@@ -2007,6 +2514,7 @@ vector Scoreboard_MapStats_Draw(vector pos, vector rgb, vector bg_size) {
        panel_size.x += panel_bg_padding * 2; // restore initial width
        return end_pos;
 }
+*/
 
 vector Scoreboard_Rankings_Draw(vector pos, string ranktitle, entity pl, vector rgb, vector bg_size)
 {
@@ -2166,10 +2674,14 @@ bool Scoreboard_AccuracyStats_WouldDraw(float ypos)
 bool have_item_stats;
 bool Scoreboard_ItemStats_WouldDraw(float ypos)
 {
+       Inventory g_inventory = inventoryslots[current_player];
+       
        if (MUTATOR_CALLHOOK(DrawScoreboardItemStats))
                return false;
        if (!autocvar_hud_panel_scoreboard_itemstats || !g_inventory || warmup_stage || ypos > 0.91 * vid_conheight)
                return false;
+       if (gametype == MAPINFO_TYPE_DUEL) // z411 : We already show items in our duel scoreboard.
+               return false;
 
        if (time < scoreboard_time + autocvar_hud_panel_scoreboard_itemstats_showdelay
                && ypos > autocvar_hud_panel_scoreboard_itemstats_showdelay_minpos * vid_conheight
@@ -2323,16 +2835,35 @@ void Scoreboard_Draw()
        sb_gameinfo_type_fontsize = hud_fontsize * 2.5;
        sb_gameinfo_detail_fontsize = hud_fontsize * 1.3;
 
+       // z411 server name
+       //drawcolorcodedstring(pos, "bienvenidoainternet.org", sb_gameinfo_type_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+       //drawpic_aspect(pos + '1 0 0' * (panel_size.x - 150), "gfx/bai_logo", vec2(150, sb_gameinfo_type_fontsize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       //pos.y += sb_gameinfo_type_fontsize.y;
+       
        // Game Info: Game Type
        if (scoreboard_ui_enabled == 2)
                str = _("Team Selection");
        else
                str = MapInfo_Type_ToText(gametype);
        draw_beginBoldFont();
-       drawcolorcodedstring(pos + '0.5 0 0' * (panel_size.x - stringwidth(str, true, sb_gameinfo_type_fontsize)), str, sb_gameinfo_type_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+       //drawcolorcodedstring(pos + '0.5 0 0' * (panel_size.x - stringwidth(str, true, sb_gameinfo_type_fontsize)), str, sb_gameinfo_type_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+       drawcolorcodedstring(pos, str, sb_gameinfo_type_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
        draw_endBoldFont();
-
+       
+       vector tmp_old_sz = draw_getimagesize("gfx/bai_logo");
+       float tmp_aspect = tmp_old_sz.x/tmp_old_sz.y;
+       vector tmp_new_sz = vec2(sb_gameinfo_type_fontsize.y * tmp_aspect, sb_gameinfo_type_fontsize.y);
+
+       // z411 Server logo
+       drawpic(pos + '1 0 0' * (panel_size.x - tmp_new_sz.x), "gfx/bai_logo", tmp_new_sz, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       
        pos.y += sb_gameinfo_type_fontsize.y;
+       
+       // z411 servername
+       drawcolorcodedstring(pos + '0.5 0 0' * (panel_size.x - stringwidth_colors(hostname_full, sb_gameinfo_detail_fontsize)), hostname_full, sb_gameinfo_detail_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+       
+       pos.y += sb_gameinfo_detail_fontsize.y;
+       
        // Game Info: Game Detail
        if (scoreboard_ui_enabled == 2)
        {
@@ -2376,6 +2907,7 @@ void Scoreboard_Draw()
                                str = strcat(str, Scoreboard_Fraglimit_Draw(ll, true));
                        }
                }
+
                drawcolorcodedstring(pos + '1 0 0' * (panel_size.x - stringwidth(str, true, sb_gameinfo_detail_fontsize)), str, sb_gameinfo_detail_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); // align right
                // map name and player count
                if (campaign)
@@ -2405,7 +2937,7 @@ void Scoreboard_Draw()
                if (autocvar_hud_panel_scoreboard_team_size_position != 1) // team size not on left
                {
                        // put team score to the left of scoreboard (and team size to the right)
-                       team_score_baseoffset = eY * hud_fontsize.y - eX * hud_fontsize.x * 0.5;
+                       team_score_baseoffset = eY * hud_fontsize.y - eX * hud_fontsize.x * 1.5;
                        team_size_baseoffset = eY * hud_fontsize.y + eX * hud_fontsize.x * 0.5;
                        if(panel.current_panel_bg != "0")
                        {
@@ -2416,7 +2948,7 @@ void Scoreboard_Draw()
                else
                {
                        // put team score to the right of scoreboard (and team size to the left)
-                       team_score_baseoffset = eY * hud_fontsize.y + eX * hud_fontsize.x * 0.5;
+                       team_score_baseoffset = eY * hud_fontsize.y + eX * hud_fontsize.x * 1.5;
                        team_size_baseoffset = eY * hud_fontsize.y - eX * hud_fontsize.x * 0.5;
                        if(panel.current_panel_bg != "0")
                        {
@@ -2441,20 +2973,20 @@ void Scoreboard_Draw()
                        if(!tm.team)
                                continue;
 
-                       draw_beginBoldFont();
                        vector rgb = Team_ColorRGB(tm.team);
+                       /*draw_beginBoldFont();
                        str = ftos(tm.(teamscores(ts_primary)));
                        if (autocvar_hud_panel_scoreboard_team_size_position != 1) // team size not on left
                        {
                                // team score on the left (default)
-                               str_pos = pos + team_score_baseoffset - eX * stringwidth(str, false, hud_fontsize * 1.5);
+                               str_pos = pos + team_score_baseoffset - eX * stringwidth(str, false, hud_fontsize * 3);
                        }
                        else
                        {
                                // team score on the right
-                               str_pos = pos + team_score_baseoffset + eX * (panel_size.x + hud_fontsize.x * 1.5);
+                               str_pos = pos + team_score_baseoffset + eX * (panel_size.x + hud_fontsize.x * 3);
                        }
-                       drawstring(str_pos, str, hud_fontsize * 1.5, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring(str_pos, str, hud_fontsize * 3, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
 
                        // team size (if set to show on the side)
                        if (autocvar_hud_panel_scoreboard_team_size_position != 0) // team size not off
@@ -2497,6 +3029,31 @@ void Scoreboard_Draw()
                                drawstring(str_pos, str, hud_fontsize, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
                        draw_endBoldFont();
+                       */
+                       
+                       // z411 My team header
+                       // Score: highlight
+                       drawfill(pos, team_score_size, rgb * 0.5, sbt_highlight_alpha, DRAWFLAG_NORMAL);
+                       
+                       // Score: text
+                       str = ftos(tm.(teamscores(ts_primary)));
+                       str_pos = pos;
+                       str_pos.x += (team_score_size.x / 2) - (stringwidth(str, true, team_score_fontsize) / 2);
+                       str_pos.y += (team_score_size.y / 2) - (team_score_fontsize.y / 2);
+                       
+                       draw_beginBoldFont();
+                       drawstring(str_pos, str, team_score_fontsize, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       draw_endBoldFont();
+                       
+                       // Team name
+                       str = Team_CustomName(tm.team);
+                       str_pos = pos;
+                       str_pos.x += team_score_size.x + team_name_fontsize.x * 0.5;
+                       str_pos.y += (team_score_size.y / 2) - (team_name_fontsize.y / 2);
+                       drawcolorcodedstring(str_pos, str, team_name_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       
+                       pos.y += team_score_size.y + (hud_fontsize.y * 0.5);
+                       
                        if(autocvar_hud_panel_scoreboard_bg_teams_color_team > 0)
                                panel_bg_color = rgb * autocvar_hud_panel_scoreboard_bg_teams_color_team;
                        else if(panel_bg_color_team > 0)
@@ -2507,6 +3064,15 @@ void Scoreboard_Draw()
                }
                panel_bg_color = panel_bg_color_save;
        }
+       else if(gametype == MAPINFO_TYPE_DUEL)
+       {
+               for(tm = teams.sort_next; tm; tm = tm.sort_next)
+                       if(tm.team != NUM_SPECTATOR)
+                               break;
+               
+               // z411 make DUEL TABLE
+               pos = Scoreboard_MakeDuelTable(pos, tm, panel_bg_color, bg_size);
+       }
        else
        {
                for(tm = teams.sort_next; tm; tm = tm.sort_next)
@@ -2517,6 +3083,8 @@ void Scoreboard_Draw()
                pos = Scoreboard_MakeTable(pos, tm, panel_bg_color, bg_size);
        }
 
+       pos = Scoreboard_MedalStats_Draw(pos);
+       
        // draw scoreboard spectators before accuracy and item stats
        if (autocvar_hud_panel_scoreboard_spectators_position == 0) {
                pos = Scoreboard_Spectators_Draw(pos);
@@ -2563,7 +3131,7 @@ void Scoreboard_Draw()
                pos = Scoreboard_Spectators_Draw(pos);
        }
 
-       pos = Scoreboard_MapStats_Draw(pos, panel_bg_color, bg_size);
+       //pos = Scoreboard_MapStats_Draw(pos, panel_bg_color, bg_size);
 
        // draw scoreboard spectators after mapstats
        if (autocvar_hud_panel_scoreboard_spectators_position == 3) {
diff --git a/qcsrc/client/hud/panel/spect.qc b/qcsrc/client/hud/panel/spect.qc
new file mode 100644 (file)
index 0000000..fc67de3
--- /dev/null
@@ -0,0 +1,387 @@
+#include "spect.qh"
+
+#include <client/hud/hud.qh>
+#include <client/view.qh>
+#include <client/draw.qh>
+#include <client/shownames.qh>
+#include <client/hud/panel/healtharmor.qh>
+#include <common/ent_cs.qh>
+#include <common/gamemodes/gamemode/duel/duel.qh>
+#include <common/resources/cl_resources.qh>
+
+vector teamscore_size;
+vector teamscore_fontsize;
+vector teamname_fontsize;
+
+void HUD_SpectHUD_Export(int fh)
+{
+       // allow saving cvars that aesthetically change the panel into hud skin files
+}
+
+void HUD_SpectHUD_drawCurrentName(vector pos)
+{
+       vector tmp;
+       string s;
+       
+       tmp = pos;
+       
+       s = entcs_GetName(current_player);
+       tmp.x -= stringwidth_colors(s, hud_fontsize * 2) / 2;
+       drawcolorcodedstring(tmp, s, hud_fontsize * 2, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+       tmp = pos;
+       s = (entcs_GetRank(current_player) != "" ? entcs_GetRank(current_player) : "Spectating");
+       tmp.x -= stringwidth_colors(s, hud_fontsize) / 2;
+       tmp.y -= hud_fontsize.y;
+       drawcolorcodedstring(tmp, s, hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+       
+void HUD_SpectHUD_drawTeamPlayers(vector pos, entity tm, vector rgb, bool invert)
+{
+       vector tmp_over;
+       vector line_sz = vec2((vid_conwidth - 1) / 7, hud_fontsize.y * 1.5);
+       vector line_sz_sub = vec2((vid_conwidth - 1) / 7, hud_fontsize.y);
+       
+       string playername;
+       float a = panel_fg_alpha * 0.8;
+       entity pl;
+       
+       if(invert)
+               pos.x -= line_sz.x + hud_fontsize.x;
+       else
+               pos.x += hud_fontsize.x;        
+       
+       for(pl = players.sort_next; pl; pl = pl.sort_next)
+       {
+               if(pl.team != tm.team)
+                       continue;
+               
+               float health = 0;
+               float armor = 0;
+               string icon = "";
+               vector icon_size = '0 0 0';
+               vector icon_rgb = '1 1 1';
+               
+               // Position and size calculation vectors
+               tmp_over = pos;
+               vector total_sz = vec2(line_sz.x, line_sz.y + line_sz_sub.y);
+               
+               bool dead = entcs_IsDead(pl.sv_entnum) || pl.eliminated;
+               
+               if(dead) {
+                       // z411 TODO : Unhardcode luma
+                       icon = "gfx/hud/luma/notify_death.tga";
+                       icon_rgb = rgb;
+               } else {
+                       entity entcs = entcs_receiver(pl.sv_entnum);
+                       if(entcs.m_entcs_private) {
+                               health = (min(entcs.healthvalue, autocvar_hud_panel_healtharmor_maxhealth) / autocvar_hud_panel_healtharmor_maxhealth) * line_sz.x;
+                               armor = (min(GetResource(entcs, RES_ARMOR), autocvar_hud_panel_healtharmor_maxarmor) / autocvar_hud_panel_healtharmor_maxarmor) * line_sz_sub.x;
+                                       
+                               Weapon wep = REGISTRY_GET(Weapons, entcs.activewepid);
+                               icon = strcat("gfx/hud/luma/", wep.model2);
+                       } else {
+                               if(tm.team == NUM_TEAM_1)
+                                       icon = "gfx/hud/luma/player_red";
+                               else if(tm.team == NUM_TEAM_2)
+                                       icon = "gfx/hud/luma/player_blue";
+                               else if(tm.team == NUM_TEAM_3)
+                                       icon = "gfx/hud/luma/player_yellow";
+                               else if(tm.team == NUM_TEAM_4)
+                                       icon = "gfx/hud/luma/player_pink";
+                               else
+                                       icon = "gfx/hud/luma/player_neutral";
+                       }
+               }
+               
+               // Draw weapon
+               if(icon != "")  {
+                       vector tmp_sz = draw_getimagesize(icon);
+                       icon_size = vec2(total_sz.y*(tmp_sz.x/tmp_sz.y), total_sz.y);
+                       total_sz.x += icon_size.x;
+                               
+                       if(invert) {
+                               pos.x -= icon_size.x;
+                               tmp_over.x -= icon_size.x;
+                       }
+                       drawpic(pos, icon, icon_size, icon_rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       pos.x += icon_size.x;
+               }
+               
+               // Get player's name
+               string playername;
+               if(entcs_GetRank(pl.sv_entnum) != "")
+                       playername = strcat(entcs_GetRank(pl.sv_entnum), "^7 ", entcs_GetName(pl.sv_entnum));
+               else
+                       playername = entcs_GetName(pl.sv_entnum);
+
+               playername = textShortenToWidth(playername, line_sz.x * 0.8, hud_fontsize, stringwidth_colors);
+               
+               // Draw health and name
+               drawfill(pos, line_sz, rgb * 0.7, a * 0.3, DRAWFLAG_NORMAL);
+               if(health)
+                       drawfill(pos, vec2(health, line_sz.y), rgb * 0.7, a, DRAWFLAG_NORMAL);
+               drawcolorcodedstring(pos + eY * ((line_sz.y - hud_fontsize.y) / 2) + eX * (hud_fontsize.x * 0.5), playername, hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+               pos.y += line_sz.y;
+               
+               // Draw armor
+               if(armor)
+                       drawfill(pos, vec2(armor, line_sz_sub.y), rgb, a, DRAWFLAG_NORMAL);
+               
+               // Highlight current player
+               if(pl.sv_entnum == current_player && spectatee_status != -1)
+                       drawfill(tmp_over, total_sz, '1 1 1', 0.3, DRAWFLAG_NORMAL);
+               if(dead || pl.eliminated)
+                       drawfill(tmp_over, total_sz, '0 0 0', 0.4, DRAWFLAG_NORMAL);
+               
+               if(!invert)
+                       pos.x -= icon_size.x;
+               pos.y += line_sz_sub.y * 2;
+       }
+}
+
+
+void HUD_SpectHUD_drawTeamScore(vector pos, entity tm, vector rgb, bool invert)
+{
+       if(!tm) return;
+       
+       vector tmp;
+       string tmp_str;
+       
+       // Team score
+       tmp_str = ftos(tm.(teamscores(ts_primary)));
+       
+       if(invert)
+               pos.x -= teamscore_size.x;
+       
+       drawfill(pos, teamscore_size, rgb * 0.8, 0.3, DRAWFLAG_NORMAL);
+       
+       tmp = pos;
+       tmp.x += (teamscore_size.x - stringwidth(tmp_str, true, teamscore_fontsize)) / 2;
+       tmp.y += (teamscore_size.y - teamscore_fontsize.y) / 2;
+               
+       draw_beginBoldFont();
+       drawstring(tmp, tmp_str, teamscore_fontsize, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+       draw_endBoldFont();
+       
+       // Team name
+       tmp_str = Team_CustomName(tm.team);
+       
+       tmp = pos;
+       if(invert)
+               tmp.x -= stringwidth_colors(tmp_str, teamname_fontsize) + teamname_fontsize.x * 0.5;
+       else
+               tmp.x += teamscore_size.x + teamname_fontsize.x * 0.5;
+       tmp.y += (teamscore_size.y - teamname_fontsize.y) / 2;
+       
+       drawcolorcodedstring(tmp, tmp_str, teamname_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
+void HUD_SpectHUD_drawDuelScore(vector pos, entity pl, bool invert)
+{
+       if(!pl) return;
+       
+       vector tmp, tmp_in;
+       string tmp_str;
+       vector health_sz = vec2((vid_conwidth - 1) / 6, teamscore_size.y * 0.4);
+       vector armor_sz = vec2(health_sz.x, health_sz.y / 4);
+       vector total_sz = vec2(health_sz.x + teamscore_size.x + (teamscore_size.x * 0.1), teamscore_size.y);
+       
+       float health = 0;
+       float armor = 0;
+       
+       entity entcs = entcs_receiver(pl.sv_entnum);
+       if(entcs.m_entcs_private) {
+               health = (min(entcs.healthvalue, autocvar_hud_panel_healtharmor_maxhealth) / autocvar_hud_panel_healtharmor_maxhealth) * health_sz.x;
+               armor = (min(GetResource(entcs, RES_ARMOR), autocvar_hud_panel_healtharmor_maxarmor) / autocvar_hud_panel_healtharmor_maxarmor) * armor_sz.x;
+       }
+       
+       if(invert)
+               pos.x -= teamscore_size.x;
+       
+       // Highlight current player
+       tmp = pos;
+       if(invert) tmp.x -= health_sz.x + (teamscore_size.x * 0.1);
+       
+       if(pl.sv_entnum == current_player && spectatee_status != -1)
+               drawfill(tmp, total_sz, '1 1 1', 0.3, DRAWFLAG_NORMAL);
+
+       if(entcs_IsDead(pl.sv_entnum))
+               drawfill(tmp, total_sz, '0 0 0', 0.4, DRAWFLAG_NORMAL);
+       
+       // Player score
+       tmp_str = ftos(pl.(scores(ps_primary)));
+       
+       drawfill(pos, teamscore_size, '0 0 0', 0.3, DRAWFLAG_NORMAL);
+       
+       tmp = pos;
+       tmp.x += (teamscore_size.x - stringwidth(tmp_str, true, teamscore_fontsize)) / 2;
+       tmp.y += (teamscore_size.y - teamscore_fontsize.y) / 2;
+               
+       draw_beginBoldFont();
+       drawstring(tmp, tmp_str, teamscore_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       draw_endBoldFont();
+       
+       // Player health/armor
+       tmp_in = pos;
+       tmp_in.y += ((teamscore_size.y / 2) - health_sz.y) / 2;
+       
+       // Background
+       tmp = tmp_in;
+       if(invert)
+               tmp.x -= health_sz.x;
+       else
+               tmp.x += teamscore_size.x;
+       
+       drawfill(tmp, health_sz, '0 0 0', 0.3, DRAWFLAG_NORMAL);
+       
+       // Bars
+       if(health) {
+               tmp = tmp_in;
+               if(invert)
+                       tmp.x -= health;
+               else
+                       tmp.x += teamscore_size.x;
+       
+               drawfill(tmp, vec2(health, health_sz.y), autocvar_hud_progressbar_health_color, 0.7, DRAWFLAG_NORMAL);
+       }
+       
+       if(armor) {
+               tmp = tmp_in;
+               //tmp.y += health_sz.y - armor_sz.y;
+               tmp.y += health_sz.y;
+               
+               if(invert)
+                       tmp.x -= armor;
+               else
+                       tmp.x += teamscore_size.x;
+               
+               drawfill(tmp, vec2(armor, armor_sz.y), autocvar_hud_progressbar_armor_color, 0.7, DRAWFLAG_NORMAL);
+       }
+       
+       // Align vertically
+       tmp = pos;
+       tmp.y += ((teamscore_size.y / 2) - teamname_fontsize.y) / 2;
+       tmp.y += teamscore_size.y / 2;
+       
+       // RJZ rank
+       string rank_str = entcs_GetRank(pl.sv_entnum);
+       if(rank_str != "") {
+               if(invert)
+                       tmp.x -= stringwidth_colors(rank_str, teamname_fontsize) + teamname_fontsize.x * 0.5;
+               else
+                       tmp.x += teamscore_size.x + teamname_fontsize.x * 0.5;
+               
+               draw_beginBoldFont();
+               drawcolorcodedstring(tmp, rank_str, teamname_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+               draw_endBoldFont();
+       }
+       
+       // Player name
+       tmp_str = entcs_GetName(pl.sv_entnum);
+       
+       if(invert)
+               tmp.x -= stringwidth_colors(tmp_str, teamname_fontsize) + teamname_fontsize.x * 0.5;
+       else
+               tmp.x += (rank_str != "" ? stringwidth_colors(rank_str, teamname_fontsize) : teamscore_size.x) + teamname_fontsize.x * 0.5;
+       
+       drawcolorcodedstring(tmp, tmp_str, teamname_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
+void HUD_SpectHUD()
+{
+       if(!spectatee_status) return;
+       
+       vector pos, rgb;
+       float ammo_y, timer_width;
+       entity tm;
+       
+       // Set main vars
+       HUD_Panel_LoadCvars();
+       HUD_Scale_Enable();
+       hud_fontsize = HUD_GetFontsize("hud_fontsize");
+       
+       // Spectator name
+       if (autocvar_hud_panel_spect_playername)
+       {
+               if(spectatee_status != -1) {
+                       ammo_y = stov(cvar_string("hud_panel_ammo_pos")).y * vid_conheight;
+                       pos = panel_pos + vec2((vid_conwidth - 1) / 2, (ammo_y - (hud_fontsize.y * 2)));
+                       HUD_SpectHUD_drawCurrentName(pos);
+               }
+       }
+       
+       // Scores
+       if (!autocvar_hud_panel_spect_scores) return;
+       if (teamplay)
+       {
+               // Set vars
+               teamscore_fontsize = hud_fontsize * 3;
+               teamname_fontsize = hud_fontsize * 2;
+               teamscore_size = vec2(teamscore_fontsize.x * 1.5, teamscore_fontsize.y * 1.25);
+               timer_width = stov(cvar_string("hud_panel_timer_size")).x * vid_conwidth;
+               
+               // Team 1
+               pos = panel_pos + vec2((vid_conwidth - 1) / 2, 0);
+               tm = GetTeam(NUM_TEAM_1, false);
+               rgb = Team_ColorRGB(tm.team);
+               pos.x -= (timer_width * 1.3) / 2;
+               HUD_SpectHUD_drawTeamScore(pos, tm, rgb, true);
+               
+               pos = panel_pos + vec2(0, (vid_conheight - 1) / 4 + hud_fontsize.y);
+               HUD_SpectHUD_drawTeamPlayers(pos, tm, rgb, false);
+               
+               // Team 2
+               pos = panel_pos + vec2((vid_conwidth - 1) / 2, 0);
+               tm = GetTeam(NUM_TEAM_2, false);
+               rgb = Team_ColorRGB(tm.team);
+               pos.x += (timer_width * 1.3) / 2;
+               HUD_SpectHUD_drawTeamScore(pos, tm, rgb, false);
+               
+               pos = panel_pos + vec2(vid_conwidth - 1, (vid_conheight - 1) / 4 + hud_fontsize.y);
+               HUD_SpectHUD_drawTeamPlayers(pos, tm, rgb, true);
+
+               // Team 3
+               pos = panel_pos + vec2((vid_conwidth - 1) / 2, 41);
+               tm = GetTeam(NUM_TEAM_3, false);
+               rgb = Team_ColorRGB(tm.team);
+               pos.x -= (timer_width * 1.3) / 2;
+               HUD_SpectHUD_drawTeamScore(pos, tm, rgb, true);
+               
+               pos = panel_pos + vec2(0, (vid_conheight + 450) / 4 + hud_fontsize.y);
+               HUD_SpectHUD_drawTeamPlayers(pos, tm, rgb, false);
+
+               // Team 4
+               pos = panel_pos + vec2((vid_conwidth - 1) / 2, 41);
+               tm = GetTeam(NUM_TEAM_4, false);
+               rgb = Team_ColorRGB(tm.team);
+               pos.x += (timer_width * 1.3) / 2;
+               HUD_SpectHUD_drawTeamScore(pos, tm, rgb, false);
+               
+               pos = panel_pos + vec2(vid_conwidth - 1, (vid_conheight + 450) / 4 + hud_fontsize.y);
+               HUD_SpectHUD_drawTeamPlayers(pos, tm, rgb, true);
+       } else if(gametype == MAPINFO_TYPE_DUEL) {
+               // Set vars
+               teamscore_fontsize = hud_fontsize * 3;
+               teamname_fontsize = hud_fontsize * 1.5;
+               teamscore_size = vec2(teamscore_fontsize.x * 1.5, teamscore_fontsize.y * 1.25);
+               timer_width = stov(cvar_string("hud_panel_timer_size")).x * vid_conwidth;
+               
+               entity pl_left = players.sort_next;
+               entity pl_right = pl_left.sort_next;
+       
+               // Left player
+               if(pl_left && (entcs_GetSpecState(pl_left.sv_entnum)) != ENTCS_SPEC_PURE) {
+                       pos = panel_pos + vec2((vid_conwidth - 1) / 2, 0);
+                       pos.x -= (timer_width * 1.3) / 2;
+                       HUD_SpectHUD_drawDuelScore(pos, pl_left, true);
+               }
+               
+               // Right player
+               if(pl_right && (entcs_GetSpecState(pl_right.sv_entnum)) != ENTCS_SPEC_PURE) {
+                       pos = panel_pos + vec2((vid_conwidth - 1) / 2, 0);
+                       pos.x += (timer_width * 1.3) / 2;
+                       HUD_SpectHUD_drawDuelScore(pos, pl_right, false);
+               }
+       }
+}
diff --git a/qcsrc/client/hud/panel/spect.qh b/qcsrc/client/hud/panel/spect.qh
new file mode 100644 (file)
index 0000000..6db88c6
--- /dev/null
@@ -0,0 +1,2 @@
+#pragma once
+#include "../panel.qh"
index 269d12b5edc800f9f2d50df6e7e70faad317bbb2..003f1c4b736662ff8a9754be77bfeda5881e2b39 100644 (file)
@@ -5,6 +5,8 @@
 #include <client/view.qh>
 
 // Timer (#5)
+float last_timeleft;
+int autocvar_cl_timer_countdown = 3; // 0 = disabled, 1 = always on, 2 = only spec, 3 = as dictated by server
 
 void HUD_Timer_Export(int fh)
 {
@@ -70,6 +72,7 @@ void HUD_Timer()
        vector timer_color = '1 1 1';
        vector subtimer_color = '1 1 1';
        bool swap = (autocvar_hud_panel_timer_secondary == 2 && STAT(ROUNDSTARTTIME));
+       float timeout_last = STAT(TIMEOUT_LAST);
 
        // Use real or frozen time and get the time limit
        curtime = (intermission_time ? intermission_time : time);
@@ -82,8 +85,26 @@ void HUD_Timer()
        if(!intermission_time && !warmup_stage && timelimit > 0)
                timer_color = HUD_Timer_Color(timeleft);
 
+       // countdown sound
+       // if 3 use server dictated option, otherwise the client's
+       int countdown_type;
+       if(autocvar_cl_timer_countdown == 3)
+               countdown_type = sv_timer_countdown;
+       else
+               countdown_type = autocvar_cl_timer_countdown;
+       
+       if(countdown_type && !warmup_stage && timeleft > 0 && timeleft != last_timeleft && timeleft <= 10 && !intermission_time)
+       {
+               if(countdown_type == 1 || (countdown_type == 2 && spectatee_status))
+                       sound(NULL, CH_INFO, SND_ENDCOUNT, VOL_BASE, ATTN_NONE);
+               
+               last_timeleft = timeleft;
+       }
+
        // Timer text
-       if (autocvar_hud_panel_timer_increment || timelimit <= 0)
+       if (timelimit == -1)
+               timer = (autocvar_hud_panel_timer_increment ? 0 : STAT(TIMELIMIT) * 60);
+       else if (autocvar_hud_panel_timer_increment || timelimit <= 0)
                timer = HUD_Timer_TimeElapsed(curtime, STAT(GAMESTARTTIME));
        else
                timer = timeleft;
@@ -96,12 +117,19 @@ void HUD_Timer()
                        subtimer_str = "--:--";
                        subtimer_color = '1 0 0';
                } else {
-                       float round_curtime, round_timelimit, round_timeleft;
+                       float round_curtime, round_endtime, round_timelimit, round_timeleft;
 
                        // Use real or frozen time and get the time limit
-                       round_curtime = (game_stopped_time ? game_stopped_time : time);
+                       round_endtime = STAT(ROUNDENDTIME);
                        round_timelimit = STAT(ROUND_TIMELIMIT);
 
+                       if(round_endtime)
+                               round_curtime = round_endtime;
+                       else if(timeout_last)
+                               round_curtime = timeout_last;
+                       else
+                               round_curtime = time;
+
                        // Calculate time left
                        round_timeleft = HUD_Timer_TimeLeft(round_curtime, STAT(ROUNDSTARTTIME), round_timelimit);
 
@@ -121,26 +149,13 @@ void HUD_Timer()
        int overtimes = STAT(OVERTIMES);
 
        if(warmup_stage || autocvar__hud_configure)
-       {
-               if (STAT(WARMUP_TIMELIMIT) > 0)
-                       subtext = _("Warmup");
-               else
-               {
-                       Scoreboard_UpdatePlayerTeams(); // ensure numplayers is current
-                       if (srv_minplayers - numplayers > 0)
-                               subtext = _("Warmup: too few players");
-                       else
-                               subtext = _("Warmup: no time limit");
-               }
-       }
+               subtext = _("Warmup");
        else if(STAT(TIMEOUT_STATUS) == 2)
                subtext = _("Timeout");
-       else if (overtimes == -1)
-               subtext = _("Sudden Death");
-       else if(overtimes == 1)
-               subtext = _("Overtime");
-       else if (overtimes >= 2)
+       else if(overtimes >= 2)
                subtext = sprintf(_("Overtime #%d"), overtimes);
+       else if(overtimes != 0)
+               subtext = _("Overtime");
 
        subtext_size  = vec2(mySize.x, mySize.y / 3);
        timer_size    = vec2(mySize.x, mySize.y - subtext_size.y);
index 2863f62d9fe160f50797762a34120c37c2b803a5..8deaebbcfe1ae9011b681a208aaa220b5f005ad0 100644 (file)
@@ -118,6 +118,8 @@ string cl_weaponpriority_old;
 bool weapons_orderbyimpulse_old;
 void HUD_Weapons()
 {
+       if(spectatee_status && teamplay) return; // z411
+       
        // declarations
        WepSet weapons_stat = WepSet_GetFromStat();
        int i;
@@ -521,7 +523,7 @@ void HUD_Weapons()
                }
 
                // draw the weapon accuracy
-               if(autocvar_hud_panel_weapons_accuracy)
+               /* z411 if(autocvar_hud_panel_weapons_accuracy)
                {
                        float panel_weapon_accuracy = weapon_accuracy[it.m_id-WEP_FIRST];
                        if(panel_weapon_accuracy >= 0)
@@ -529,7 +531,7 @@ void HUD_Weapons()
                                color = Accuracy_GetColor(panel_weapon_accuracy);
                                drawpic_aspect_skin(weapon_pos, "weapon_accuracy", weapon_size, color, panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
-               }
+               }*/
 
                vector weapon_size_real = noncurrent_size;
                float weapon_alpha_real = noncurrent_alpha;
index 90917341a29a67bbc69e9f0cc74a05328015cd0c..f16b86ed6a6a2b9b0b3f87214ff740f7095f6c21 100644 (file)
@@ -99,6 +99,9 @@ void CSQC_Init()
        registercvar("cl_weapon_switch_fallback_to_impulse", "1");
 
        registercvar("cl_allow_uidranking", "1");
+       
+       // z411
+       registercvar("cl_chat_sounds", "1");
 
        if(autocvar_cl_lockview)
                cvar_set("cl_lockview", "0");
@@ -796,6 +799,8 @@ NET_HANDLE(ENT_CLIENT_RANDOMSEED, bool isnew)
 NET_HANDLE(ENT_CLIENT_ACCURACY, bool isnew)
 {
        make_pure(this);
+       float entnum = ReadByte();
+       
        int sf = ReadInt24_t();
        if (sf == 0) {
                for (int w = 0; w <= WEP_LAST - WEP_FIRST; ++w)
@@ -806,13 +811,22 @@ NET_HANDLE(ENT_CLIENT_ACCURACY, bool isnew)
        int f = 1;
        for (int w = 0; w <= WEP_LAST - WEP_FIRST; ++w) {
                if (sf & f) {
-                       int b = ReadByte();
-                       if (b == 0)
-                               weapon_accuracy[w] = -1;
-                       else if (b == 255)
-                               weapon_accuracy[w] = 1.0; // no better error handling yet, sorry
-                       else
-                               weapon_accuracy[w] = (b - 1.0) / 100.0;
+                       if(entnum > 0) {
+                               playerslots[entnum-1].accuracy_frags[w] = ReadByte();
+                               playerslots[entnum-1].accuracy_hit[w] = ReadShort();
+                               playerslots[entnum-1].accuracy_cnt_hit[w] = ReadShort();
+                               playerslots[entnum-1].accuracy_cnt_fired[w] = ReadShort();
+                               
+                               //LOG_INFOF("Duel stats ?/%d", playerslots[entnum-1].accuracy_cnt_fired[w]);
+                       } else {
+                               int b = ReadByte();
+                               if (b == 0)
+                                       weapon_accuracy[w] = -1;
+                               else if (b == 255)
+                                       weapon_accuracy[w] = 1.0; // no better error handling yet, sorry
+                               else
+                                       weapon_accuracy[w] = (b - 1.0) / 100.0;
+                       }
                }
                f = (f == 0x800000) ? 1 : f * 2;
        }
@@ -1129,6 +1143,11 @@ NET_HANDLE(ENT_CLIENT_INIT, bool isnew)
        serverflags = ReadByte();
 
        g_trueaim_minrange = ReadCoord();
+       
+       strcpy(hostname_full, ReadString());
+       strcpy(motd_permanent, ReadString());
+       
+       sv_timer_countdown = ReadByte();
 
        return = true;
 
@@ -1137,6 +1156,27 @@ NET_HANDLE(ENT_CLIENT_INIT, bool isnew)
        if (!postinit) PostInit();
 }
 
+NET_HANDLE(TE_CSQC_TEAMNAMES, bool isNew)
+{
+       teamname_red = strzone(ReadString());
+       teamname_blue = strzone(ReadString());
+       teamname_yellow = strzone(ReadString());
+       teamname_pink = strzone(ReadString());
+
+       return = true;
+}
+
+NET_HANDLE(TE_CSQC_CHATSOUND, bool isNew)
+{
+       string snd = ReadString();
+       snd = strcat("chat/", snd, ".ogg");
+       
+       precache_sound(snd);
+       _sound(NULL, CH_INFO, snd, VOL_BASE, ATTN_NONE);
+
+       return = true;
+}
+
 float GetSpeedUnitFactor(int speed_unit)
 {
        switch(speed_unit)
index 7929a450e078d0a9bc339b3f583858e7aae3ab6d..6774e757d1bda53f63937a43dce02f19a11f0398 100644 (file)
@@ -2,6 +2,12 @@
 
 #include <common/constants.qh>
 #include <common/weapons/_all.qh>
+#include <common/items/inventory.qh>
+
+// z411
+string hostname_full;
+string motd_permanent;
+int sv_timer_countdown;
 
 bool autocvar_cl_db_saveasdump;
 bool autocvar_cl_spawn_event_particles;
@@ -168,8 +174,16 @@ string GetSpeedUnit(int speed_unit);
 .int enttype; // entity type sent from server
 .int sv_entnum; // entity number sent from server
 
+// z411 accuracy info
+.float accuracy_frags[REGISTRY_MAX(Weapons)];
+.float accuracy_hit[REGISTRY_MAX(Weapons)];
+.float accuracy_cnt_hit[REGISTRY_MAX(Weapons)];
+.float accuracy_cnt_fired[REGISTRY_MAX(Weapons)];
+
 .int team;
 .int team_size;
+.int countrycode;
+.string rank;
 
 int binddb;
 
@@ -193,3 +207,4 @@ float serverprevtime, serverdeltatime;
 float ticrate;
 
 int serverflags;
+
index bf6e22c61c9cfd655b09a98ab879b0cddaca9f76..1d8e8d66f9b83de111adf7a1200f92138bd0a0b7 100644 (file)
@@ -857,7 +857,7 @@ void HitSound()
        float kill_time = STAT(KILL_TIME);
        if (COMPARE_INCREASING(kill_time, kill_time_prev) > autocvar_cl_hitsound_antispam_time)
        {
-               sound(NULL, CH_INFO, SND_KILL, VOL_BASE, ATTN_NONE);
+               sound(NULL, CH_INFO, SND_KILL, VOL_BASE * 1.15, ATTN_NONE);
                kill_time_prev = kill_time;
        }
 }
@@ -1167,6 +1167,12 @@ void HUD_Damage()
                        myhealth_flash += autocvar_hud_damage_fade_rate * frametime; // dead
                }
        }
+       
+       if(myhealth_prev > 1 && myhealth <= 0 && !intermission)
+       {
+               // Just died
+               sound(NULL, CH_INFO, SND_DEATH, VOL_BASE, ATTN_NONE);
+       }
 
        if(spectatee_status == -1 || intermission)
        {
index b775b9686af21c166eaccff8b3da1688cba3d83c..8cf3a631bc0ba7e9bae3035be491358b4446f0b1 100644 (file)
@@ -1,5 +1,7 @@
 noref float autocvar_net_connecttimeout = 30;
 
+#include "announcer.qc"
+#include "colors.qc"
 #include "checkextension.qc"
 
 #ifdef GAMEQC
diff --git a/qcsrc/common/announcer.qc b/qcsrc/common/announcer.qc
new file mode 100644 (file)
index 0000000..02583c3
--- /dev/null
@@ -0,0 +1,45 @@
+//FEATURE: Custom default announcers on the server side, that clients can override if desired
+
+#ifdef GAMEQC
+REGISTER_MUTATOR(announcer, true);
+#endif
+
+#ifdef SVQC
+
+AUTOCVAR(sv_announcer, string, "", "Force client announcer to this");
+
+MUTATOR_HOOKFUNCTION(announcer, Ent_Init, CBC_ORDER_FIRST)
+{
+       WriteString(MSG_ONE, autocvar_sv_announcer);
+}
+
+#elif defined(CSQC)
+
+string sv_announcer;
+
+AUTOCVAR_SAVE(cl_announcer_force,                    bool,   false,      "Don't allow server to override default announcer");
+
+void Announcer_Precache()
+{
+       FOREACH(Notifications, it.nent_type == MSG_ANNCE, {
+               if(it.nent_enabled)
+                       precache_sound(sprintf("announcer/%s/%s.wav", AnnouncerOption(), it.nent_snd));
+       });
+}
+
+MUTATOR_HOOKFUNCTION(announcer, AnnouncerOption)
+{
+       if(autocvar_cl_announcer_force || sv_announcer == "" || !sv_announcer || autocvar_cl_announcer != "default")
+               return false;
+
+       M_ARGV(0, string) = sv_announcer;
+}
+
+MUTATOR_HOOKFUNCTION(announcer, Ent_Init, CBC_ORDER_FIRST)
+{
+       sv_announcer = strzone(ReadString());
+
+       if(sv_announcer != "" && sv_announcer) { Announcer_Precache(); }
+}
+
+#endif
diff --git a/qcsrc/common/colors.qc b/qcsrc/common/colors.qc
new file mode 100644 (file)
index 0000000..f60dd35
--- /dev/null
@@ -0,0 +1,181 @@
+#ifdef GAMEQC
+
+string mod_translate_clean(string s)
+{
+       if(ColorTranslateMode & 1)
+               return strdecolorize(s);
+
+       if(s == "" || !s)
+               return s;
+
+       s = strreplace("^x664", "^7", s);
+       s = strreplace("^x665", "^3", s);
+       s = strreplace("^x666", "^1", s);
+       s = strreplace("^x667", "^2", s);
+       s = strreplace("^x668", "^4", s);
+       s = strreplace("^x669", "^0", s);
+       return s;
+}
+
+string mod_playername(string thename, int teamid, bool team_colorize)
+{
+    TC(int, teamid);
+       bool do_colorize = (teamplay && team_colorize && Team_IsValidTeam(teamid));
+    
+#ifdef SVQC
+       if(do_colorize && !intermission_running)
+#else
+       if(do_colorize)
+#endif
+    {
+        string t = Team_ColorCode(teamid);
+        return strcat(t, strdecolorize(thename));
+    }
+    else
+        return mod_translate_clean(thename);
+}
+
+#endif
+
+#ifdef CSQC
+AUTOCVAR(cl_stripfancystuff, bool, false, "Turn off the fancy blinking colorful names");
+
+vector mod_get_num_color(int num)
+{
+       vector color;
+       float thenum = 0;
+       switch(num)
+       {
+               case 1: color = vec3(sin(2 * M_PI * time), 1, sin(2 * M_PI * time)); thenum = 200; break;
+               default:
+               case 2: color = '1 0 0'; thenum = 1; break;
+               case 3: color = '0 0 1'; thenum = 1; break;
+               case 4: color = vec3(1, 1, sin(2 * M_PI * time)); thenum = 200; break;
+               case 5: color = vec3(sin(2 * M_PI * time), sin(2 * M_PI * time), sin(2 * M_PI * time)); thenum = 200; break;
+               case 6: color = '1 1 1'; thenum = 1; break;
+        case 7: color = vec3(0.69, 0.12, sin(2 * M_PI * time)); thenum = 200; break;
+       }
+
+       float blinkingamt = (1 - thenum/200/0.25);
+       if(blinkingamt > 0)
+       {
+               color.x = color.x - color.x * blinkingamt * sin(2*M_PI*time);
+               color.y = color.y - color.y * blinkingamt * sin(2*M_PI*time);
+               color.z = color.z - color.z * blinkingamt * sin(2*M_PI*time);
+       }
+       return color;
+}
+
+string mod_translate(string s)
+{
+       if(autocvar_cl_stripfancystuff)
+               return mod_translate_clean(s);
+
+       if(ColorTranslateMode & 1)
+               return strdecolorize(s);
+
+       if(s == "" || !s)
+               return s;
+
+       string theword = "";
+       int fancy = 0;
+       FOREACH_CHAR(s, true,
+       {
+               string realch = chr2str(it);
+               if(realch == "^")
+               {
+                       string nc1 = chr2str(str2chr(iter_s, iter_i));
+                       string nc2 = chr2str(str2chr(iter_s, iter_i + 1));
+                       string nc3 = chr2str(str2chr(iter_s, iter_i + 2));
+                       string nc4 = chr2str(str2chr(iter_s, iter_i + 3));
+                       int fc4 = stoi(nc4);
+                       if(nc1 == "x" && nc2 == "6" && nc3 == "6" && (fc4 >= 3 && fc4 <= 9)) // so far so good
+                       {
+                               switch(fc4)
+                               {
+                    case 3: fancy = 7; break;
+                                       case 4: fancy = 6; break;
+                                       case 5: fancy = 4; break;
+                                       default:
+                                       case 6: fancy = 2; break;
+                                       case 7: fancy = 1; break;
+                                       case 8: fancy = 3; break;
+                                       case 9: fancy = 5; break;
+                               }
+                               int pos = iter_i + 4; // skip the color code
+                               STRING_ITERATOR_LOAD(iter, pos);
+                               continue;
+                       }
+                       else
+                       {
+                               fancy = 0;
+                               // not a valid hax, but also a color, add normally and continue!
+                               theword = strcat(theword, realch);
+                               continue;
+                       }
+               }
+               else if(fancy)
+               {
+                       vector thecolor = mod_get_num_color(fancy);
+                       thecolor.x = bound(0, thecolor.x, 1);
+                       thecolor.y = bound(0, thecolor.y, 1);
+                       thecolor.z = bound(0, thecolor.z, 1);
+                       theword = strcat(theword, rgb_to_hexcolor(thecolor), strdecolorize(realch));
+               }
+               else
+                       theword = strcat(theword, realch);
+       });
+
+       return theword;
+}
+
+void mod_parse_print(string strMessage)
+{
+       if (autocvar_developer_csqcentities) LOG_INFOF("CSQC_Parse_Print(\"%s\")", strMessage);
+       print(mod_translate_clean(strMessage));
+}
+
+string mod_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...
+       input = mod_translate_clean(input);
+       return input;
+}
+#endif
+
+STATIC_INIT_LATE(mod_functions_override)
+{
+#ifdef CSQC
+       ColorTranslateRGB = mod_translate;
+       CSQC_Parse_Print = mod_parse_print;
+       CCR = mod_ccr;
+       //Scoreboard_GetName = mod_scoreboard_getname;
+#elif defined(SVQC)
+       playername = mod_playername;
+#endif
+}
+
+#ifdef SVQC
+REGISTER_MUTATOR(namecolors, true);
+MUTATOR_HOOKFUNCTION(namecolors, PreFormatMessage)
+{
+       string themsg = mod_translate_clean(M_ARGV(1, string));
+
+       M_ARGV(1, string) = themsg;
+}
+#endif
index 85119de08825c52ab9c6692d87d4d9a3eb9fd83b..3dfea8f98973ff4288dc0a527668e82242d950f1 100644 (file)
@@ -151,12 +151,29 @@ ENTCS_PROP(CLIENTCOLORS, true, clientcolors, clientcolors, ENTCS_SET_NORMAL,
 ENTCS_PROP(FRAGS, true, frags, frags, ENTCS_SET_NORMAL,
        { WriteShort(chan, ent.frags); },
        { ent.frags = ReadShort(); })
+       
+ENTCS_PROP(COUNTRYCODE, true, countrycode, countrycode, ENTCS_SET_NORMAL,
+       { WriteByte(chan, ent.countrycode); },
+       { ent.countrycode = ReadByte(); })
+
+ENTCS_PROP(RANK, true, rank, rank, ENTCS_SET_NORMAL,
+       { WriteString(chan, ent.rank); },
+       { strcpy(ent.rank, ReadString()); })
+
+ENTCS_PROP(WANTSJOIN, true, wants_join, wants_join, ENTCS_SET_NORMAL,
+       { WriteByte(chan, ent.wants_join); },
+       { ent.wants_join = ReadByte(); })
 
 // use sv_solid to avoid changing solidity state of entcs entities
 ENTCS_PROP(SOLID, true, sv_solid, solid, ENTCS_SET_NORMAL,
        { WriteByte(chan, ent.sv_solid); },
        { ent.sv_solid = ReadByte(); })
 
+// z411 weapon
+ENTCS_PROP(ACTIVEWEPID, false, activewepid, activewepid, ENTCS_SET_NORMAL,
+       { WriteByte(chan, ent.activewepid); },
+       { ent.activewepid = ReadByte(); })
+
 #ifdef SVQC
 
        int ENTCS_PUBLICMASK = 0, ENTCS_PRIVATEMASK = 0;
index aa689e59d707684eda169334528faf49cce8eefe..8c5259fcdd37b8a788a04448868181231729fcda 100644 (file)
@@ -18,6 +18,7 @@ REGISTER_NET_TEMP(CLIENT_ENTCS)
 .bool has_sv_origin;
 #endif
 .int sv_solid;
+.int activewepid; // z411
 
 #ifdef SVQC
 /*
@@ -71,6 +72,7 @@ REGISTER_NET_TEMP(CLIENT_ENTCS)
      * @param i zero indexed player
      */
     .int frags;
+    .int wants_join;
        const int ENTCS_SPEC_PURE = 1; // real spectator
        const int ENTCS_SPEC_IN_SCOREBOARD = 2; // spectator but still in game (can be in a team)
        #define entcs_IsSpectating(i) boolean(entcs_GetSpecState(i))
@@ -90,6 +92,15 @@ REGISTER_NET_TEMP(CLIENT_ENTCS)
 
        /**
      * @param i zero indexed player
+     */
+       int entcs_GetWantsJoin(int i)
+       {
+               entity e = entcs_receiver(i);
+               return e.wants_join;
+       }
+
+       /**
+     * @param i zero indexed player
      */
        int entcs_GetClientColors(int i)
        {
@@ -132,6 +143,18 @@ REGISTER_NET_TEMP(CLIENT_ENTCS)
                entity e = entcs_receiver(i);
                return e ? ColorTranslateRGB(e.netname) : "";
        }
+       
+       int entcs_GetCountryCode(int i)
+       {
+               entity e = entcs_receiver(i);
+               return e.countrycode;
+       }
+       
+       string entcs_GetRank(int i)
+       {
+               entity e = entcs_receiver(i);
+               return e.rank;
+       }
 
     /**
      * @param i zero indexed player
index c91d9a33c2a4b6edfcf6d0bfb53f6aa7a50dfada..7cfdc7b30d376cddc68820cb33c279cb5c418bae 100644 (file)
@@ -1,6 +1,6 @@
 #include "cl_clanarena.qh"
 
-#include <client/draw.qh>
+/*#include <client/draw.qh>
 
 #include <common/mutators/base.qh>
 
@@ -88,3 +88,18 @@ void HUD_Mod_CA(vector myPos, vector mySize)
 
        HUD_Mod_CA_Draw(myPos, mySize, autocvar_hud_panel_modicons_ca_layout);
 }
+*/
+// Clan Arena and Freeze Tag scores
+int HUD_Scores_CA(int team)
+{
+       switch(team)
+       {
+               case NUM_TEAM_1: return STAT(REDALIVE);
+               case NUM_TEAM_2: return STAT(BLUEALIVE);
+               case NUM_TEAM_3: return STAT(YELLOWALIVE);
+               default:
+               case NUM_TEAM_4: return STAT(PINKALIVE);
+       }
+       
+       return 0;
+}
\ No newline at end of file
index 586d7eb17eb8e5fa025ef0fd70adef0b4095f90b..f55c3585f7de941397ca677bbd129160e9efba82 100644 (file)
@@ -1,7 +1,3 @@
 #pragma once
 
-int autocvar_hud_panel_modicons_ca_layout;
-
-void HUD_Mod_CA(vector myPos, vector mySize);
-void HUD_Mod_CA_Draw(vector myPos, vector mySize, int layout);
-void HUD_Mod_CA_Export(int fh);
+int HUD_Scores_CA(int team);
index b3a8635a14a396f3e55d5093a1809c627cc7e529..095d043b7128b69363a1b9ead5a18ac02b868bca 100644 (file)
@@ -3,8 +3,9 @@
 #include <common/mapinfo.qh>
 
 #ifdef CSQC
-void HUD_Mod_CA(vector pos, vector mySize);
-void HUD_Mod_CA_Export(int fh);
+//void HUD_Mod_CA(vector pos, vector mySize);
+//void HUD_Mod_CA_Export(int fh);
+int HUD_Scores_CA(int team);
 #endif
 CLASS(ClanArena, Gametype)
     INIT(ClanArena)
@@ -40,8 +41,9 @@ CLASS(ClanArena, Gametype)
         returns(menu, _("Round limit:"),     5,  100,  5, "fraglimit_override",        "g_ca_teams_override",          _("The amount of rounds won needed before the match will end"));
     }
 #ifdef CSQC
-    ATTRIB(ClanArena, m_modicons, void(vector pos, vector mySize), HUD_Mod_CA);
-    ATTRIB(ClanArena, m_modicons_export, void(int fh), HUD_Mod_CA_Export);
+    //ATTRIB(ClanArena, m_modicons, void(vector pos, vector mySize), HUD_Mod_CA);
+    //ATTRIB(ClanArena, m_modicons_export, void(int fh), HUD_Mod_CA_Export);
+    ATTRIB(ClanArena, m_modscores, int(int team), HUD_Scores_CA);
 #endif
     ATTRIB(ClanArena, m_legacydefaults, string, "10 20 0");
 ENDCLASS(ClanArena)
index 8ee0a676569b8364f931e52b7a976c87d2f858ef..2c4a097d6f5fe4dde48b81bcc46ca9ba8d93d331 100644 (file)
@@ -20,15 +20,22 @@ void CA_count_alive_players()
        for (int i = 1; i <= NUM_TEAMS; ++i)
        {
                Team_SetNumberOfAlivePlayers(Team_GetTeamFromIndex(i), 0);
+               Team_SetNumberOfPlayers(Team_GetTeamFromIndex(i), 0);
        }
-       FOREACH_CLIENT(IS_PLAYER(it) && Entity_HasValidTeam(it),
+       FOREACH_CLIENT(Entity_HasValidTeam(it),
        {
                ++total_players;
-               if (IS_DEAD(it))
+               entity team_ = Entity_GetTeam(it);
+               
+               int num_total = Team_GetNumberOfPlayers(team_);
+               ++num_total;
+               Team_SetNumberOfPlayers(team_, num_total);
+               
+               if (IS_DEAD(it) || !IS_PLAYER(it))
                {
                        continue;
                }
-               entity team_ = Entity_GetTeam(it);
+               
                int num_alive = Team_GetNumberOfAlivePlayers(team_);
                ++num_alive;
                Team_SetNumberOfAlivePlayers(team_, num_alive);
@@ -44,6 +51,22 @@ void CA_count_alive_players()
 
 void nades_Clear(entity player);
 
+entity ca_LastPlayer(float tm)
+{
+       entity last_pl = NULL;
+       FOREACH_CLIENT(IS_PLAYER(it) && it.team == tm, {
+               if (!IS_DEAD(it))
+               {
+                       if (!last_pl)
+                               last_pl = it;
+                       else
+                               return NULL;
+               }
+       });
+       return last_pl;
+}
+
+
 int CA_PreventStalemate()
 {
        //bprint("PreventStalemate running\n");
@@ -159,28 +182,59 @@ float CA_CheckWinner()
        if (!winner_team)
                return 0;
 
+       bool perfect = false;
        if(winner_team > 0)
        {
+               entity tm = Team_GetTeam(winner_team);
+               entity last_pl = ca_LastPlayer(winner_team);
+               
+               if(last_pl && Team_GetNumberOfPlayers(tm) >= 3) {
+                       Give_Medal(last_pl, DEFENSE);
+               }
+               
                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
+               if(fragsleft > 1) Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, APP_TEAM_NUM(winner_team, ANNCE_ROUND_TEAM_WIN));
                TeamScore_AddToTeam(winner_team, ST_CA_ROUNDS, +1);
+               
+               if (Team_GetNumberOfPlayers(tm) >= 3 &&
+                       Team_GetNumberOfAlivePlayers(tm) == Team_GetNumberOfPlayers(tm))
+                               perfect = true;
        }
        else if(winner_team == -1)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_TIED);
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_TIED);
+               Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_ROUND_TIED);
        }
        else if(winner_team == -2)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
+               Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_ROUND_OVER);
        }
 
        allowed_to_spawn = false;
-       game_stopped = true;
+       if(autocvar_g_ca_round_stop)
+               game_stopped = true;
        round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
 
-       FOREACH_CLIENT(IS_PLAYER(it), { nades_Clear(it); });
+       FOREACH_CLIENT(IS_PLAYER(it), {
+               nades_Clear(it);
+               
+               // Give perfect medal if everyone in the winner team is alive
+               if(perfect && it.team == winner_team) {
+                       Give_Medal(it, PERFECT);
+               }
+               
+               // Give accuracy medal for each weapon above 50%
+               entity ra = it.roundaccuracy;
+               for (int w = 0; w <= WEP_LAST - WEP_FIRST; ++w) {
+                       if(ra.accuracy_fired[w] > 1 && (ra.accuracy_hit[w] / ra.accuracy_fired[w]) > 0.5) {
+                               Give_Medal(it, ACCURACY);
+                       }
+               }
+       });
 
        return 1;
 }
@@ -313,6 +367,12 @@ MUTATOR_HOOKFUNCTION(ca, reset_map_players)
        return true;
 }
 
+MUTATOR_HOOKFUNCTION(ca, Scores_CountFragsRemaining)
+{
+       // announce remaining frags
+       return true;
+}
+
 MUTATOR_HOOKFUNCTION(ca, reset_map_global)
 {
        allowed_to_spawn = true;
@@ -345,8 +405,10 @@ void ca_LastPlayerForTeam_Notify(entity this)
        if (!warmup_stage && round_handler_IsActive() && round_handler_IsRoundStarted())
        {
                entity pl = ca_LastPlayerForTeam(this);
-               if (pl)
+               if (pl) {
                        Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE);
+                       Send_Notification(NOTIF_ONE, pl, MSG_ANNCE, ANNCE_ALONE);
+               }
        }
 }
 
@@ -526,12 +588,6 @@ MUTATOR_HOOKFUNCTION(ca, PlayerRegen)
        return true;
 }
 
-MUTATOR_HOOKFUNCTION(ca, Scores_CountFragsRemaining)
-{
-       // announce remaining frags
-       return true;
-}
-
 MUTATOR_HOOKFUNCTION(ca, SpectateSet)
 {
        entity client = M_ARGV(0, entity);
index 3a9931e431c6bda42a895c42603c92242cf7a573..4b84d51605a374aba61fce36d508eac3551c30f2 100644 (file)
@@ -10,6 +10,7 @@ int autocvar_g_ca_spectate_enemies;
 int autocvar_g_ca_point_limit;
 int autocvar_g_ca_point_leadlimit;
 float autocvar_g_ca_round_timelimit;
+bool autocvar_g_ca_round_stop;
 bool autocvar_g_ca_team_spawns;
 //int autocvar_g_ca_teams;
 int autocvar_g_ca_teams_override;
@@ -40,6 +41,8 @@ REGISTER_MUTATOR(ca, false)
                ca_teams = autocvar_g_ca_teams_override;
                if (ca_teams < 2)
                        ca_teams = cvar("g_ca_teams"); // read the cvar directly as it gets written earlier in the same frame
+               if (autocvar_g_ca_spectate_enemies == -1)
+                       observe_blocked_if_eliminated = true;
 
                ca_teams = BITS(bound(2, ca_teams, 4));
         GameRules_scoring(ca_teams, SFL_SORT_PRIO_PRIMARY, 0, {
index 4bea0edf4e3bfe1d89d12c45904693245d80f5ac..ded4971847a887655434f67626c2d100a0325e86 100644 (file)
@@ -620,6 +620,11 @@ void ctf_Handle_Capture(entity flag, entity toucher, int capturetype)
        new_time = TIME_ENCODE(time - enemy_flag.ctf_pickuptime);
        if(!old_time || new_time < old_time)
                GameRules_scoring_add(player, CTF_CAPTIME, new_time - old_time);
+       
+       Give_Medal(player, CAPTURE);
+       
+       // announcer
+       AnnounceScores(player.team);
 
        // effects
        Send_Effect_(flag.capeffect, flag.origin, '0 0 0', 1);
@@ -634,7 +639,10 @@ void ctf_Handle_Capture(entity flag, entity toucher, int capturetype)
                if(flag.speedrunning) { ctf_FakeTimeLimit(player, -1); }
 
                if((enemy_flag.ctf_dropper) && (player != enemy_flag.ctf_dropper))
-                       { GameRules_scoring_add_team(enemy_flag.ctf_dropper, SCORE, ((enemy_flag.score_assist) ? enemy_flag.score_assist : autocvar_g_ctf_score_capture_assist)); }
+               {
+                       GameRules_scoring_add_team(enemy_flag.ctf_dropper, SCORE, ((enemy_flag.score_assist) ? enemy_flag.score_assist : autocvar_g_ctf_score_capture_assist));
+                       Give_Medal(enemy_flag.ctf_dropper, ASSIST);
+               }
        }
 
        flag.enemy = toucher;
@@ -655,6 +663,14 @@ void ctf_Handle_Return(entity flag, entity player)
        {
                Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, CENTER_CTF_RETURN));
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(flag.team, INFO_CTF_RETURN), player.netname);
+               
+               FOREACH_CLIENT(IS_PLAYER(it), {
+                       if(it.team == flag.team)
+                               Send_Notification(NOTIF_ONE_ONLY, it, MSG_ANNCE, ANNCE_CTF_RETURN_TEAM);
+                       else
+                               Send_Notification(NOTIF_ONE_ONLY, it, MSG_ANNCE, ANNCE_CTF_RETURN_ENEMY);
+               });
+               Send_Notification(NOTIF_ALL_SPEC, NULL, MSG_ANNCE, APP_TEAM_NUM(flag.team, ANNCE_CTF_RETURN));
        }
        _sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTEN_NONE);
        ctf_EventLog("return", flag.team, player);
@@ -724,16 +740,22 @@ void ctf_Handle_Pickup(entity flag, entity player, int pickuptype)
 
        // messages and sounds
        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_PICKUP), player.netname);
+       Send_Notification(NOTIF_ALL_SPEC, NULL, MSG_ANNCE, APP_TEAM_NUM(flag.team, ANNCE_CTF_PICKUP));
+       
        if(ctf_stalemate)
                Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_STALEMATE_CARRIER);
        if(!flag.team)
                Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_NEUTRAL);
        else if(CTF_DIFFTEAM(player, flag))
+       {
                Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, CENTER_CTF_PICKUP));
+               Send_Notification(NOTIF_ONE_ONLY, player, MSG_ANNCE, ANNCE_CTF_PICKUP_YOU);
+       }
        else
                Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((SAME_TEAM(player, flag)) ? CENTER_CTF_PICKUP_RETURN : CENTER_CTF_PICKUP_RETURN_ENEMY), Team_ColorCode(flag.team));
 
        Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, APP_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
+       Send_Notification(NOTIF_TEAM_ONLY_EXCEPT, player, MSG_ANNCE, ANNCE_CTF_PICKUP_TEAM);
 
        if(!flag.team)
                FOREACH_CLIENT(IS_PLAYER(it) && it != player && DIFF_TEAM(it, player), { Send_Notification(NOTIF_ONE, it, MSG_CHOICE, CHOICE_CTF_PICKUP_ENEMY_NEUTRAL, Team_ColorCode(player.team), player.netname); });
@@ -741,9 +763,15 @@ void ctf_Handle_Pickup(entity flag, entity player, int pickuptype)
        if(flag.team)
                FOREACH_CLIENT(IS_PLAYER(it) && it != player, {
                        if(CTF_SAMETEAM(flag, it))
-                               Send_Notification(NOTIF_ONE, it, MSG_CHOICE, ((SAME_TEAM(flag, player)) ? CHOICE_CTF_PICKUP_ENEMY_TEAM : CHOICE_CTF_PICKUP_ENEMY), Team_ColorCode(player.team), player.netname);
-                       else if(DIFF_TEAM(player, it))
-                               Send_Notification(NOTIF_ONE, it, MSG_CHOICE, APP_NUM(flag.team, CHOICE_CTF_PICKUP_ENEMY_OTHER), Team_ColorCode(player.team), player.netname);
+                       {
+                               if(SAME_TEAM(player, it)) {
+                                       Send_Notification(NOTIF_ONE, it, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
+                                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_ANNCE, ANNCE_CTF_PICKUP_TEAM);
+                               } else {
+                                       Send_Notification(NOTIF_ONE, it, MSG_CHOICE, ((SAME_TEAM(flag, player)) ? CHOICE_CTF_PICKUP_ENEMY_TEAM : CHOICE_CTF_PICKUP_ENEMY), Team_ColorCode(player.team), player.netname);
+                                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_ANNCE, ANNCE_CTF_PICKUP_ENEMY);
+                               }
+                       }
                });
 
        _sound(player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTEN_NONE);
@@ -2255,10 +2283,26 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerDies)
        entity frag_attacker = M_ARGV(1, entity);
        entity frag_target = M_ARGV(2, entity);
 
-       if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)) && (frag_target.flagcarried))
-       {
-               GameRules_scoring_add_team(frag_attacker, SCORE, ((SAME_TEAM(frag_attacker, frag_target)) ? -autocvar_g_ctf_score_kill : autocvar_g_ctf_score_kill));
-               GameRules_scoring_add(frag_attacker, CTF_FCKILLS, 1);
+       if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)))
+       {
+               if(frag_target.flagcarried) {
+                       // Killing an enemy flag carrier
+                       GameRules_scoring_add_team(frag_attacker, SCORE, ((SAME_TEAM(frag_attacker, frag_target)) ? -autocvar_g_ctf_score_kill : autocvar_g_ctf_score_kill));
+                       GameRules_scoring_add(frag_attacker, CTF_FCKILLS, 1);
+               } else if(frag_attacker.flagcarried) {
+                       Give_Medal(frag_attacker, DEFENSE);
+               } else {
+                       entity tmp_entity;
+                       for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
+                       if(tmp_entity.ctf_status == FLAG_BASE && CTF_SAMETEAM(tmp_entity, frag_attacker))
+                       {
+                               if(CTF_IS_NEAR(frag_target, tmp_entity, '1 1 1' * 1500))
+                               {
+                                       Give_Medal(frag_attacker, DEFENSE);
+                               }
+                               break;
+                       }
+               }
        }
 
        if(frag_target.flagcarried)
@@ -2267,6 +2311,7 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerDies)
                ctf_Handle_Throw(frag_target, NULL, DROP_NORMAL);
                tmp_entity.ctf_dropper = NULL;
        }
+       
 }
 
 MUTATOR_HOOKFUNCTION(ctf, GiveFragsForKill)
index adb061809fe053f56c36f763e31fb7195e0e3928..cd503721622c97dd5ced19bd8940a5270d8b40b9 100644 (file)
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "ctf.qh"
+
 #include <common/items/item/pickup.qh>
 #include <common/mutators/base.qh>
 #include <common/gamemodes/sv_rules.qh>
@@ -176,3 +177,5 @@ void havocbot_role_ctf_setrole(entity bot, int role);
 // team checking
 #define CTF_SAMETEAM(a,b) ((autocvar_g_ctf_reverse || (ctf_oneflag && autocvar_g_ctf_oneflag_reverse)) ? DIFF_TEAM(a,b) : SAME_TEAM(a,b))
 #define CTF_DIFFTEAM(a,b) ((autocvar_g_ctf_reverse || (ctf_oneflag && autocvar_g_ctf_oneflag_reverse)) ? SAME_TEAM(a,b) : DIFF_TEAM(a,b))
+#define CTF_IS_NEAR(player, it, extra_size) \
+       boxesoverlap(player.absmin - extra_size, player.absmax + extra_size, it.absmin, it.absmax)
index e622a1942fbee46b6c792aae8abe47df0cad0c83..d82143d8091faf62d29c5d751853da0819a83f87 100644 (file)
@@ -5,3 +5,44 @@ MUTATOR_HOOKFUNCTION(dm, Scores_CountFragsRemaining)
        // announce remaining frags
        return true;
 }
+
+MUTATOR_HOOKFUNCTION(dm, Scores_AnnounceLeads)
+{
+       // enable leads announcer
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(dm, FragCenterMessage)
+{
+       // Use normal notifications in warmup
+       if(warmup_stage) return false;
+       
+       entity attacker = M_ARGV(0, entity);
+       entity targ = M_ARGV(1, entity);
+       //float frag_deathtype = M_ARGV(2, float);
+       int kill_count_to_attacker = M_ARGV(3, int);
+       int kill_count_to_target = M_ARGV(4, int);
+       
+       Send_Notification(
+               NOTIF_ONE,
+               attacker,
+               MSG_CENTER,
+               CENTER_DEATH_MURDER_DM,
+               targ.netname,
+               kill_count_to_attacker,
+               GameRules_scoring_add(attacker, SCORE, 0)
+       );
+       Send_Notification(
+               NOTIF_ONE,
+               targ,
+               MSG_CHOICE,
+               CHOICE_FRAGGED,
+               attacker.netname,
+               kill_count_to_target,
+               GetResource(attacker, RES_HEALTH),
+               GetResource(attacker, RES_ARMOR),
+               (IS_BOT_CLIENT(attacker) ? -1 : CS(attacker).ping)
+       );
+       
+       return true;
+}
index fc662e2a9fa826648cebfcb875b493ef1a4c40db..75531a292c100772fab3cce0d4aba7331c9afa47 100644 (file)
@@ -11,6 +11,12 @@ MUTATOR_HOOKFUNCTION(duel, Scores_CountFragsRemaining)
        return true;
 }
 
+MUTATOR_HOOKFUNCTION(duel, Scores_AnnounceLeads)
+{
+       // enable leads announcer
+       return true;
+}
+
 MUTATOR_HOOKFUNCTION(duel, FilterItemDefinition)
 {
        entity definition = M_ARGV(0, entity);
@@ -20,3 +26,48 @@ MUTATOR_HOOKFUNCTION(duel, FilterItemDefinition)
                return !autocvar_g_duel_with_powerups;
        }
 }
+
+MUTATOR_HOOKFUNCTION(duel, FragCenterMessage)
+{
+       // Use normal notifications in warmup
+       if(warmup_stage) return false;
+       
+       entity attacker = M_ARGV(0, entity);
+       entity targ = M_ARGV(1, entity);
+       string tie_str;
+       int kill_count_to_attacker = M_ARGV(3, int);
+       int kill_count_to_target = M_ARGV(4, int);
+       
+       WinningConditionHelper(NULL);
+       
+       if(WinningConditionHelper_equality)
+               tie_str = "^3Tied";
+       else if(attacker == WinningConditionHelper_winner)
+               tie_str = "^2Leads";
+       else
+               tie_str = "^1Trails";
+       
+       Send_Notification(
+               NOTIF_ONE,
+               attacker,
+               MSG_CENTER,
+               CENTER_DEATH_MURDER_DUEL,
+               targ.netname,
+               tie_str,
+               kill_count_to_attacker,
+               GameRules_scoring_add(attacker, SCORE, 0)
+       );
+       Send_Notification(
+               NOTIF_ONE,
+               targ,
+               MSG_CHOICE,
+               CHOICE_FRAGGED,
+               attacker.netname,
+               kill_count_to_target,
+               GetResource(attacker, RES_HEALTH),
+               GetResource(attacker, RES_ARMOR),
+               (IS_BOT_CLIENT(attacker) ? -1 : CS(attacker).ping)
+       );
+       
+       return true;
+}
index df4931a37133793b69a021ed28d66d106b70beee..85dbd463424fee4a177abee36088c62da47abb65 100644 (file)
@@ -1,8 +1,8 @@
 #include "cl_freezetag.qh"
 
-#include <common/gamemodes/gamemode/clanarena/cl_clanarena.qh>
+//#include <common/gamemodes/gamemode/clanarena/cl_clanarena.qh>
 
-void HUD_Mod_FreezeTag_Export(int fh)
+/*void HUD_Mod_FreezeTag_Export(int fh)
 {
        HUD_Write_Cvar("hud_panel_modicons_freezetag_layout");
 }
@@ -12,4 +12,5 @@ void HUD_Mod_FreezeTag(vector myPos, vector mySize)
        mod_active = 1; // required in each mod function that always shows something
 
        HUD_Mod_CA_Draw(myPos, mySize, autocvar_hud_panel_modicons_freezetag_layout);
-}
+}*/
+
index 75bfeefd483541c7c63e88edde625730b31d2848..6f70f09beec2219624baeca92e2cd7deaa104fb4 100644 (file)
@@ -1,5 +1 @@
 #pragma once
-
-int autocvar_hud_panel_modicons_freezetag_layout;
-
-void HUD_Mod_FreezeTag_Export(int fh);
index f1723757a6024d1d0a92ed5dfbd16f26995dcd60..cde542f0772f6626e9b5fdb78f286bee3bde01f4 100644 (file)
@@ -5,10 +5,10 @@
        #include <common/gamemodes/gamemode/clanarena/cl_clanarena.qh>
 #endif
 
-#ifdef CSQC
-void HUD_Mod_FreezeTag(vector myPos, vector mySize);
-void HUD_Mod_FreezeTag_Export(int fh);
-#endif
+//#ifdef CSQC
+//void HUD_Mod_FreezeTag(vector myPos, vector mySize);
+//void HUD_Mod_FreezeTag_Export(int fh);
+//#endif
 CLASS(FreezeTag, Gametype)
     INIT(FreezeTag)
     {
@@ -43,8 +43,9 @@ CLASS(FreezeTag, Gametype)
         returns(menu, _("Round limit:"),     5,  100,  5, "fraglimit_override",        "g_freezetag_teams_override",   _("The amount of rounds won needed before the match will end"));
     }
 #ifdef CSQC
-    ATTRIB(FreezeTag, m_modicons, void(vector pos, vector mySize), HUD_Mod_FreezeTag);
-    ATTRIB(FreezeTag, m_modicons_export, void(int fh), HUD_Mod_FreezeTag_Export);
+    //ATTRIB(FreezeTag, m_modicons, void(vector pos, vector mySize), HUD_Mod_FreezeTag);
+    //ATTRIB(FreezeTag, m_modicons_export, void(int fh), HUD_Mod_FreezeTag_Export);
+    ATTRIB(FreezeTag, m_modscores, int(int team), HUD_Scores_CA);
 #endif
     ATTRIB(FreezeTag, m_legacydefaults, string, "10 20 0");
 ENDCLASS(FreezeTag)
index 3f7fff9ebe3ad5bfc01b4f1ae582c26b4b273ddb..32bd7acb218793b8365c59670d1b906f35cc4744 100644 (file)
@@ -86,18 +86,36 @@ bool freezetag_CheckTeams()
 void nades_Clear(entity);
 void nades_GiveBonus(entity player, float score);
 
+entity freezetag_LastPlayer(float tm)
+{
+       entity last_pl = NULL;
+       FOREACH_CLIENT(IS_PLAYER(it) && it.team == tm, {
+               if (STAT(FROZEN, it) != FROZEN_NORMAL && GetResource(it, RES_HEALTH) >= 1)
+               {
+                       if (!last_pl)
+                               last_pl = it;
+                       else
+                               return NULL;
+               }
+       });
+       return last_pl;
+}
+
 bool freezetag_CheckWinner()
 {
        if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
+               Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_ROUND_OVER);
+               
                FOREACH_CLIENT(IS_PLAYER(it), {
                        it.freezetag_frozen_timeout = 0;
                        it.freezetag_revive_time = 0;
                        nades_Clear(it);
                });
-               game_stopped = true;
+               if(autocvar_g_freezetag_round_stop)
+                       game_stopped = true;
                round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
                return true;
        }
@@ -108,14 +126,21 @@ bool freezetag_CheckWinner()
 
        if(winner_team > 0)
        {
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
+               entity last_pl = freezetag_LastPlayer(winner_team);
+               if(last_pl) {
+                       Give_Medal(last_pl, DEFENSE);
+               }
+       
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_SCORES));
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_SCORES));
                TeamScore_AddToTeam(winner_team, ST_FT_ROUNDS, +1);
+               if(fragsleft > 1) AnnounceScores(winner_team);
        }
        else if(winner_team == -1)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_TIED);
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_TIED);
+               Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_ROUND_TIED);
        }
 
        FOREACH_CLIENT(IS_PLAYER(it), {
@@ -124,7 +149,8 @@ bool freezetag_CheckWinner()
                nades_Clear(it);
        });
 
-       game_stopped = true;
+       if(autocvar_g_freezetag_round_stop)
+               game_stopped = true;
        round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
        return true;
 }
@@ -150,8 +176,10 @@ void freezetag_LastPlayerForTeam_Notify(entity this)
        if(round_handler_IsRoundStarted())
        {
                entity pl = freezetag_LastPlayerForTeam(this);
-               if(pl)
+               if(pl) {
                        Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE);
+                       Send_Notification(NOTIF_ONE, pl, MSG_ANNCE, ANNCE_ALONE);
+               }
        }
 }
 
@@ -446,9 +474,14 @@ MUTATOR_HOOKFUNCTION(ft, reset_map_players)
 {
        FOREACH_CLIENT(IS_PLAYER(it), {
                CS(it).killcount = 0;
-               it.freezetag_revive_time = 0;
-               it.freezetag_frozen_timeout = -1;
-               PutClientInServer(it);
+               
+               if(autocvar_g_freezetag_round_respawn) {
+                       it.freezetag_frozen_timeout = -1;
+                       PutClientInServer(it);
+               } else {
+                       ResetPlayerResources(it);
+               }
+               
                it.freezetag_frozen_timeout = 0;
        });
        freezetag_count_alive_players();
@@ -465,6 +498,12 @@ MUTATOR_HOOKFUNCTION(ft, Unfreeze)
 {
        entity targ = M_ARGV(0, entity);
        targ.freezetag_frozen_time = 0;
+       
+       if(autocvar_g_freezetag_revive_respawn) {
+               targ.freezetag_frozen_timeout = -1;
+               PutClientInServer(targ);
+       }
+       
        targ.freezetag_frozen_timeout = 0;
 }
 
@@ -650,6 +689,7 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
                        Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_REVIVED, revivers_first.netname);
                        Send_Notification(NOTIF_ONE, revivers_first, MSG_CENTER, CENTER_FREEZETAG_REVIVE, player.netname);
                        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_REVIVED, player.netname, revivers_first.netname);
+                       Give_Medal(revivers_first, ASSIST);
                        if(autocvar_sv_eventlog)
                        {
                                string revivers = "";
index 049f037147e19b22fa68d1c0c02d6004f9b30bb7..9a44134b42b968a5e12279b21da0e65ef509f446 100644 (file)
@@ -8,6 +8,9 @@ int autocvar_g_freezetag_point_leadlimit;
 bool autocvar_g_freezetag_team_spawns;
 string autocvar_g_freezetag_weaponarena = "most_available";
 
+bool autocvar_g_freezetag_round_respawn;
+bool autocvar_g_freezetag_round_stop;
+
 const int ST_FT_ROUNDS = 1;
 
 void freezetag_Initialize();
@@ -47,4 +50,5 @@ float autocvar_g_freezetag_revive_speed_t2s = 0.25;
 float autocvar_g_freezetag_revive_time_to_score = 1.5;
 bool autocvar_g_freezetag_revive_nade;
 float autocvar_g_freezetag_revive_nade_health;
+bool autocvar_g_freezetag_revive_respawn;
 float autocvar_g_freezetag_revive_spawnshield = 1;
index f06df370d0668bb271f5ad1b43e15ec6c30ea387..cb1075cd8aca5cd074b0ebdea834a89965e7cc96 100644 (file)
@@ -136,7 +136,7 @@ MUTATOR_HOOKFUNCTION(rc, PlayerPhysics)
        player.race_movetime_frac -= f;
        player.race_movetime_count += f;
        player.race_movetime = player.race_movetime_frac + player.race_movetime_count;
-
+       
        if(IS_PLAYER(player))
        {
                if (player.race_penalty)
index 5e850889679fd1ebceb5992b86cbc6f605c044a4..3bd9cb5648bad21295a2aa7ecc0e3b11251d878f 100644 (file)
@@ -70,3 +70,9 @@ MUTATOR_HOOKFUNCTION(tdm, Scores_CountFragsRemaining)
        // announce remaining frags
        return true;
 }
+
+MUTATOR_HOOKFUNCTION(tdm, Scores_AnnounceLeads)
+{
+       // enable leads announcer
+       return true;
+}
index 118b7079d0c832303ae7aa563172515fea190273..94e09e67b7595ebc230b3082dc8dc605d8913ef7 100644 (file)
@@ -14,6 +14,7 @@ ENDCLASS(Inventory)
 .Inventory inventory_store;
 
 REGISTER_NET_LINKED(ENT_CLIENT_INVENTORY)
+REGISTER_NET_TEMP(TE_CSQC_INVENTORY)
 
 const int Inventory_groups_minor = 8; // must be a multiple of 8 (one byte) to optimize bandwidth usage
 const int Inventory_groups_major = 4; // must be >= ceil(REGISTRY_COUNT(Items) / Inventory_groups_minor)
@@ -39,20 +40,19 @@ STATIC_INIT(Inventory)
 #ifdef CSQC
 #include <client/hud/panel/pickup.qh>
 
-Inventory g_inventory;
+//Inventory g_inventory;
+Inventory inventoryslots[255];
 
 void Inventory_remove(entity this)
 {
-    if(g_inventory == this)
-        g_inventory = NULL;
+    // TODO z411
+    //if(g_inventory == this)
+    //    g_inventory = NULL;
 }
 
-NET_HANDLE(ENT_CLIENT_INVENTORY, bool isnew)
+void Inventory_handle(entity inv, bool mine)
 {
-    make_pure(this);
-    g_inventory = this;
-    this.entremove = Inventory_remove;
-    const int majorBits = Readbits(Inventory_groups_major);
+       const int majorBits = Readbits(Inventory_groups_major);
     for (int i = 0; i < Inventory_groups_major; ++i) {
         if (!(majorBits & BIT(i))) {
             continue;
@@ -64,13 +64,33 @@ NET_HANDLE(ENT_CLIENT_INVENTORY, bool isnew)
             }
             const GameItem it = REGISTRY_GET(Items, Inventory_groups_minor * i + j);
             .int fld = inv_items[it.m_id];
-            int prev = this.(fld);
-            int next = this.(fld) = ReadByte();
+            int prev = inv.(fld);
+            int next = inv.(fld) = ReadByte();
 
             Pickup_Update(it, next - prev);
             LOG_DEBUGF("%s: %.0f -> %.0f", it.m_name, prev, next);
         }
     }
+}
+
+NET_HANDLE(ENT_CLIENT_INVENTORY, bool isnew)
+{
+    make_pure(this);
+    inventoryslots[current_player] = this;
+    //this.entremove = Inventory_remove; // z411 TODO : Must implement this
+
+    Inventory_handle(this, true);
+    return true;
+}
+
+NET_HANDLE(TE_CSQC_INVENTORY, bool isnew)
+{
+       float entnum = ReadByte() - 1;
+       
+       if(!inventoryslots[entnum])
+               inventoryslots[entnum] = NEW(Inventory);
+       
+       Inventory_handle(inventoryslots[entnum], entnum == current_player);
     return true;
 }
 
@@ -84,10 +104,10 @@ NET_HANDLE(TE_CSQC_WEAPONPICKUP, bool isnew)
 
 #ifdef SVQC
 int minorBitsArr[Inventory_groups_major];
-void Inventory_Write(Inventory data, Inventory store)
+void Inventory_Write(int channel, Inventory data, Inventory store)
 {
     if (!data) {
-        WriteShort(MSG_ENTITY, 0);
+        WriteShort(channel, 0);
         return;
     }
     TC(Inventory, data);
@@ -107,21 +127,21 @@ void Inventory_Write(Inventory data, Inventory store)
         }
     });
 
-       Writebits(MSG_ENTITY, majorBits, Inventory_groups_major);
+       Writebits(channel, majorBits, Inventory_groups_major);
        for (int i = 0; i < Inventory_groups_major; ++i)
        {
                if (!(majorBits & BIT(i)))
                        continue;
 
                const int minorBits = minorBitsArr[i];
-               Writebits(MSG_ENTITY, minorBits, Inventory_groups_minor);
+               Writebits(channel, minorBits, Inventory_groups_minor);
                for (int j = 0; j < Inventory_groups_minor; ++j)
                {
                        if (!(minorBits & BIT(j)))
                                continue;
 
                        const entity it = REGISTRY_GET(Items, Inventory_groups_minor * i + j);
-                       WriteByte(MSG_ENTITY, data.inv_items[it.m_id]);
+                       WriteByte(channel, data.inv_items[it.m_id]);
                }
        }
 }
@@ -131,12 +151,26 @@ void Inventory_Write(Inventory data, Inventory store)
 #undef G_MINOR
 
 #ifdef SVQC
+bool Inventory_Broadcast(Inventory this)
+{
+       TC(Inventory, this);
+    WriteHeader(MSG_BROADCAST, TE_CSQC_INVENTORY);
+    TC(PlayerState, this.owner);
+    
+    // z411 send entity number
+    WriteByte(MSG_BROADCAST, etof(this.owner.m_client));
+    
+    Inventory_Write(MSG_BROADCAST, this, this.owner.m_client.inventory_store);
+    return true;
+}
+
 bool Inventory_Send(Inventory this, Client to, int sf)
 {
     TC(Inventory, this);
     WriteHeader(MSG_ENTITY, ENT_CLIENT_INVENTORY);
     TC(PlayerState, this.owner);
-    Inventory_Write(this, to.inventory_store);
+    
+    Inventory_Write(MSG_ENTITY, this, to.inventory_store);
     return true;
 }
 
@@ -149,14 +183,23 @@ bool Inventory_customize(entity this, entity client)
 void Inventory_new(PlayerState this)
 {
     Inventory inv = NEW(Inventory);
-    setcefc(inv, Inventory_customize);
+    inv.owner = this;
        this.inventory = inv;
-       inv.owner = this;
-       Net_LinkEntity(inv, false, 0, Inventory_Send);
+    
+    if(!g_duel) {
+               setcefc(inv, Inventory_customize);
+               Net_LinkEntity(inv, false, 0, Inventory_Send);
+       }
 }
 
 void Inventory_delete(entity e) { delete(e.inventory); }
-void Inventory_update(entity e) { e.inventory.SendFlags = 0xFFFFFF; }
+void Inventory_update(entity e)
+{
+       if(g_duel)
+               Inventory_Broadcast(e.inventory);
+       else
+               e.inventory.SendFlags = 0xFFFFFF;
+}
 
 void Inventory_pickupitem(Pickup this, entity player)
 {
index 4d65695ae41a9391d19b1f145440c1942bfc5e70..bc5b500f8cede750e7e33f8e9296e72783edf72d 100644 (file)
@@ -54,9 +54,10 @@ CLASS(Gametype, Object)
     /** game type priority in random selections */
     ATTRIB(Gametype, m_priority, int, 0);
 #ifdef CSQC
-    ATTRIB(Gametype, m_modicons, void(vector pos, vector mySize));
-    ATTRIB(Gametype, m_modicons_reset, void());
-    ATTRIB(Gametype, m_modicons_export, void(int fh));
+    //ATTRIB(Gametype, m_modicons, void(vector pos, vector mySize));
+    //ATTRIB(Gametype, m_modicons_reset, void());
+    //ATTRIB(Gametype, m_modicons_export, void(int fh));
+       ATTRIB(Gametype, m_modscores, int(int team));
 #endif
 
     /** DO NOT USE, this is compatibility for legacy maps! */
index 7f00250fbf781a13a32572c71dc193b6bb483ba6..5a3fa66684c22cb3dea31773c19032ec3cc80cb3 100644 (file)
@@ -32,8 +32,8 @@
 
 void monsters_setstatus(entity this)
 {
-       STAT(MONSTERS_TOTAL, this) = monsters_total;
-       STAT(MONSTERS_KILLED, this) = monsters_killed;
+       //STAT(MONSTERS_TOTAL, this) = monsters_total;
+       //STAT(MONSTERS_KILLED, this) = monsters_killed;
 }
 
 bool autocvar_g_monsters_drop = true;
index c463c429f0c0eec1c0c1ffa89487a79158a9ae1a..57e591d48ee6c95309174dadc0117838f757823b 100644 (file)
@@ -1,5 +1,6 @@
 // generated file; do not modify
 
+#include <common/mutators/mutator/attackertext/_mod.inc>
 #include <common/mutators/mutator/bloodloss/_mod.inc>
 #include <common/mutators/mutator/breakablehook/_mod.inc>
 #include <common/mutators/mutator/buffs/_mod.inc>
index 3b4eba7cb65a6a4fa93d97e515d6bb19a7f7b347..5128166ec4e3a5b7ea397c035e6f00d3bdec0ccd 100644 (file)
@@ -4,6 +4,7 @@
 #include <common/mutators/mutator/breakablehook/_mod.qh>
 #include <common/mutators/mutator/buffs/_mod.qh>
 #include <common/mutators/mutator/bugrigs/_mod.qh>
+#include <common/mutators/mutator/attackertext/_mod.qh>
 #include <common/mutators/mutator/campcheck/_mod.qh>
 #include <common/mutators/mutator/cloaked/_mod.qh>
 #include <common/mutators/mutator/damagetext/_mod.qh>
diff --git a/qcsrc/common/mutators/mutator/attackertext/_mod.inc b/qcsrc/common/mutators/mutator/attackertext/_mod.inc
new file mode 100644 (file)
index 0000000..52b56df
--- /dev/null
@@ -0,0 +1,8 @@
+// generated file; do not modify
+#include <common/mutators/mutator/attackertext/attackertext.qc>
+#ifdef CSQC
+    #include <common/mutators/mutator/attackertext/cl_attackertext.qc>
+#endif
+#ifdef SVQC
+    #include <common/mutators/mutator/attackertext/sv_attackertext.qc>
+#endif
diff --git a/qcsrc/common/mutators/mutator/attackertext/_mod.qh b/qcsrc/common/mutators/mutator/attackertext/_mod.qh
new file mode 100644 (file)
index 0000000..e712e37
--- /dev/null
@@ -0,0 +1,11 @@
+// generated file; do not modify
+#include <common/mutators/mutator/damagetext/damagetext.qh>
+#ifdef CSQC
+    #include <common/mutators/mutator/damagetext/cl_damagetext.qh>
+#endif
+#ifdef SVQC
+    #include <common/mutators/mutator/damagetext/sv_damagetext.qh>
+#endif
+#ifdef MENUQC
+    #include <common/mutators/mutator/damagetext/ui_damagetext.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/attackertext/attackertext.qc b/qcsrc/common/mutators/mutator/attackertext/attackertext.qc
new file mode 100644 (file)
index 0000000..c026c3a
--- /dev/null
@@ -0,0 +1,5 @@
+#include "attackertext.qh"
+
+#ifdef GAMEQC
+REGISTER_NET_TEMP(attackertext)
+#endif
diff --git a/qcsrc/common/mutators/mutator/attackertext/attackertext.qh b/qcsrc/common/mutators/mutator/attackertext/attackertext.qh
new file mode 100644 (file)
index 0000000..96d63a7
--- /dev/null
@@ -0,0 +1,4 @@
+#pragma once
+
+const int ATFLAG_SAMETEAM = BIT(0);
+
diff --git a/qcsrc/common/mutators/mutator/attackertext/cl_attackertext.qc b/qcsrc/common/mutators/mutator/attackertext/cl_attackertext.qc
new file mode 100644 (file)
index 0000000..e191cf2
--- /dev/null
@@ -0,0 +1,61 @@
+#include "cl_attackertext.qh"
+
+AUTOCVAR_SAVE(cl_attackertext,                        bool,   true,       "Draw damage dealt where you hit the enemy");
+AUTOCVAR_SAVE(cl_attackertext_friendlyfire,           bool,   false,      "Show for friendlyfire");
+AUTOCVAR_SAVE(cl_attackertext_time,                   float,  3,          "Time to show");
+AUTOCVAR_SAVE(cl_attackertext_fadetime,               float,  2,          "Time to fade");
+AUTOCVAR_SAVE(cl_attackertext_decolorize,             int,    1,          "1 = decolorize names when teamplay, 2 = decolorize always");
+
+REGISTER_MUTATOR(attackertext, true);
+
+MUTATOR_HOOKFUNCTION(attackertext, DrawInfoMessages)
+{
+       if (autocvar_cl_attackertext == 0) return false;
+       
+       float fade_start = max(0, autocvar_cl_attackertext_time);
+       float fade_time = max(0, autocvar_cl_attackertext_fadetime);
+               
+       if (last_attack_time && last_attack_time > time - fade_start - fade_time) {
+               vector pos = M_ARGV(0, vector);
+               vector mySize = M_ARGV(1, vector);
+               vector fontsize = '0.3 0.3 0' * mySize.y;
+               int img_curr_group = M_ARGV(2, int);
+               
+               float alpha_ = 0;
+               
+               if (last_attack_time + fade_start > time)
+                       alpha_ = panel_fg_alpha;
+               else if (fade_time != 0)
+                       alpha_ = panel_fg_alpha - bound(0, (time - last_attack_time - fade_start) * (1 / fade_time), 1);
+               else
+                       return true;
+                       
+               pos = InfoMessages_drawstring(last_attack_name, pos, mySize, alpha_, fontsize);
+               img_curr_group = -1;
+
+               return true;
+       }
+               
+       return false;
+}
+
+
+NET_HANDLE(attackertext, bool isNew)
+{
+    int server_entity_index = ReadByte();
+       int flags = ReadByte();
+    bool friendlyfire = flags & ATFLAG_SAMETEAM;
+       
+       return = true;
+       
+    if (autocvar_cl_attackertext == 0) return;
+    if (friendlyfire && autocvar_cl_attackertext_friendlyfire == 0) return;
+       
+       string s = entcs_GetName(server_entity_index - 1);
+       if ((autocvar_cl_attackertext_decolorize == 1 && teamplay) || autocvar_cl_attackertext_decolorize == 2)
+               s = playername(s, entcs_GetTeam(server_entity_index - 1), true);
+
+       last_attack_time = time;
+       strfree(last_attack_name);
+       strcpy(last_attack_name, s);
+}
diff --git a/qcsrc/common/mutators/mutator/attackertext/cl_attackertext.qh b/qcsrc/common/mutators/mutator/attackertext/cl_attackertext.qh
new file mode 100644 (file)
index 0000000..c2c6d6e
--- /dev/null
@@ -0,0 +1,4 @@
+#pragma once
+
+float last_attack_time;
+string last_attack_name;
\ No newline at end of file
diff --git a/qcsrc/common/mutators/mutator/attackertext/sv_attackertext.qc b/qcsrc/common/mutators/mutator/attackertext/sv_attackertext.qc
new file mode 100644 (file)
index 0000000..2a2556d
--- /dev/null
@@ -0,0 +1,34 @@
+#include "sv_attackertext.qh"
+
+AUTOCVAR(sv_attackertext, int, 1, "0: disabled, 1: visible");
+
+REGISTER_MUTATOR(attackertext, true);
+
+#define SV_ATTACKERTEXT_DISABLED()        (autocvar_sv_attackertext <= 0)
+#define SV_ATTACKERTEXT_ENABLED()         (autocvar_sv_attackertext >= 1)
+
+void attackertext_Send(entity to, entity attacker, int sf)
+{
+       if(IS_REAL_CLIENT(to)) {
+               msg_entity = to;
+               WriteHeader(MSG_ONE, attackertext);
+               WriteByte(MSG_ONE, etof(attacker));
+               WriteByte(MSG_ONE, sf);
+       }
+}
+
+MUTATOR_HOOKFUNCTION(attackertext, PlayerDamaged) {
+    if (SV_ATTACKERTEXT_DISABLED()) return;
+       
+    entity attacker = M_ARGV(0, entity);
+    entity hit = M_ARGV(1, entity);
+       
+       if (hit == attacker) return;
+       if (!IS_PLAYER(attacker)) return;
+       
+       int sf = 0;
+       if (SAME_TEAM(hit, attacker)) sf |= ATFLAG_SAMETEAM;
+       
+       attackertext_Send(hit, attacker, sf);
+       FOREACH_CLIENT(IS_SPEC(it) && it.(enemy) == hit, { attackertext_Send(it, attacker, sf); });
+}
diff --git a/qcsrc/common/mutators/mutator/attackertext/sv_attackertext.qh b/qcsrc/common/mutators/mutator/attackertext/sv_attackertext.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 41ceaa91fab751c6bfa7761d77f15cdc44ff9058..3992d985a3465e90072ff699218a6f94f3bdd569 100644 (file)
@@ -14,7 +14,7 @@ MUTATOR_HOOKFUNCTION(bloodloss, PlayerPreThink)
 {
        entity player = M_ARGV(0, entity);
 
-       if(game_stopped)
+       if(game_stopped || game_timeout)
                return; // during intermission, the player's health changes to strange values for the engine, let's not cause damage during this phase!
 
        if(IS_PLAYER(player))
index e51c7cc9d6d97696511c6df3323ddbc8365aa62a..90af35f26241dce7ac94603b10671415da8e01f4 100644 (file)
@@ -151,7 +151,7 @@ void buff_SetCooldown(entity this, float cd)
 
 void buff_Respawn(entity this)
 {
-       if(game_stopped) return;
+       if(game_stopped || game_timeout) return;
 
        vector oldbufforigin = this.origin;
        this.velocity = '0 0 200';
@@ -186,7 +186,7 @@ void buff_Respawn(entity this)
 
 void buff_Touch(entity this, entity toucher)
 {
-       if(game_stopped) return;
+       if(game_stopped || game_timeout) return;
 
        if(ITEM_TOUCH_NEEDKILL())
        {
@@ -328,7 +328,7 @@ void buff_Think(entity this)
                this.oldbuffs = this.buffdef;
        }
 
-       if(!game_stopped)
+       if(!game_stopped && !game_timeout)
        if((round_handler_IsActive() && round_handler_IsRoundStarted()) || time >= game_starttime)
        if(!this.buff_activetime_updated)
        {
@@ -350,7 +350,7 @@ void buff_Think(entity this)
        }
 
        if(this.buff_activetime)
-       if(!game_stopped)
+       if(!game_stopped && !game_timeout)
        if((round_handler_IsActive() && round_handler_IsRoundStarted()) || time >= game_starttime)
        {
                this.buff_activetime = max(0, this.buff_activetime - frametime);
@@ -795,7 +795,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerUseKey, CBC_ORDER_FIRST)
 
 MUTATOR_HOOKFUNCTION(buffs, ForbidThrowCurrentWeapon)
 {
-       if(MUTATOR_RETURNVALUE || game_stopped) return;
+       if(MUTATOR_RETURNVALUE || game_stopped || game_timeout) return;
        entity player = M_ARGV(0, entity);
 
        if(StatusEffects_active(BUFF_SWAPPER, player))
@@ -924,7 +924,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
 {
        entity player = M_ARGV(0, entity);
 
-       if(game_stopped || IS_DEAD(player) || !IS_PLAYER(player)) return;
+       if(game_stopped || game_timeout || IS_DEAD(player) || frametime || !IS_PLAYER(player)) return;
 
        // NOTE: this is kept here to ensure crouches are picked up each player movement frame
        if(StatusEffects_active(BUFF_FLIGHT, player))
index 0cce4e443e76c08df38b2fa3419a3c42d86ba94d..0137a8e6c47d63506db3faa460f70b4667b27a54 100644 (file)
@@ -38,7 +38,7 @@ MUTATOR_HOOKFUNCTION(campcheck, PlayerPreThink)
        bool checked = false;
 
        if(autocvar_g_campcheck_interval)
-       if(!game_stopped && !warmup_stage && time >= game_starttime)
+       if(!game_stopped && !game_timeout && !warmup_stage && time >= game_starttime)
        if(IS_PLAYER(player) && !IS_DEAD(player) && !STAT(FROZEN, player))
        if(autocvar_g_campcheck_typecheck || !PHYS_INPUT_BUTTON_CHAT(player))
        if(IS_REAL_CLIENT(player)) // only apply to real clients (bots may "camp" due to missing waypoints in the map, but that's no reason to constantly kill them, clones can't move)
index 12d4316f4ea7a8974b0ab0a1ea64e2b0bbc7319b..491aed68786d72f4aac2380ec7472915b5a0fb2e 100644 (file)
@@ -73,7 +73,7 @@ void instagib_ammocheck(entity this)
        if(!IS_PLAYER(this))
                return; // not a player
 
-       if(IS_DEAD(this) || game_stopped)
+       if(IS_DEAD(this) || game_stopped || game_timeout)
                instagib_stop_countdown(this);
        else if (GetResource(this, RES_CELLS) > 0 || (this.items & IT_UNLIMITED_AMMO) || (this.flags & FL_GODMODE))
                instagib_stop_countdown(this);
index 5aa59bffc38eb6f29f2da638dfb25a9527d54e44..986d4c67a8ed74c2435618d03968cd07fe32d073 100644 (file)
@@ -27,6 +27,15 @@ NET_HANDLE(itemstime, bool isNew)
     return = true;
     ItemsTime_time[i] = f;
 }
+
+NET_HANDLE(TE_CSQC_TOTALSHARDS, bool isNew)
+{
+       // for RJZ
+       total_shards = ReadInt24_t();
+       
+       return = true;
+}
+
 #endif
 
 #ifdef CSQC
@@ -202,6 +211,25 @@ void HUD_ItemsTime_Export(int fh)
        HUD_Write_Cvar("hud_panel_itemstime_dynamicsize");
 }
 
+// for RJZ
+void DrawItemsTimeItemFixed(vector myPos, vector mySize, float ar, string item_icon, float t, vector color)
+{
+       vector picpos, numpos;
+    if (autocvar_hud_panel_itemstime_iconalign)
+    {
+        numpos = myPos;
+        picpos = myPos + eX * (ar - 1) * mySize_y;
+    }
+    else
+    {
+        numpos = myPos + eX * mySize_y;
+        picpos = myPos;
+    }
+    
+    drawstring_aspect(numpos, (t < 0 ? "-" : ftos(t)), vec2(((ar - 1)/ar) * mySize.x, mySize.y), color, panel_fg_alpha, DRAWFLAG_NORMAL);
+    drawpic_aspect(picpos, item_icon, '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
 void DrawItemsTimeItem(vector myPos, vector mySize, float ar, string item_icon, float item_time, bool item_available, float item_availableTime)
 {
     float t = 0;
@@ -279,7 +307,18 @@ float Item_ItemsTime_GetTime(int item)
         return -1; // don't show others
     }
     else
-        return ItemsTime_time[item];
+       {
+               float game_starttime = STAT(GAMESTARTTIME);
+               float timeout_last = STAT(TIMEOUT_LAST);
+               
+               if(ItemsTime_time[item] > 0 && game_starttime < time)
+                       if(timeout_last)
+                               return ItemsTime_time[item] + game_starttime - timeout_last + time;
+                       else
+                               return ItemsTime_time[item] + game_starttime;
+               else
+                       return ItemsTime_time[item];
+       }
 }
 
 void HUD_ItemsTime()
@@ -314,6 +353,10 @@ void HUD_ItemsTime()
         });
         count += (Item_ItemsTime_GetTime(REGISTRY_MAX(Items)) != -1);
     }
+    // for RJZ
+    if (total_shards != -1)
+               count++;
+       
     if (count == 0)
         return;
 
@@ -379,6 +422,9 @@ void HUD_ItemsTime()
             itemstime_size.y = newSize;
         }
     }
+    
+    if (total_shards != -1)
+               panel_size.y += itemstime_size.y * 0.5;
 
     HUD_Scale_Enable();
     HUD_Panel_DrawBg();
@@ -390,6 +436,7 @@ void HUD_ItemsTime()
     FOREACH(Items, Item_ItemsTime_Allow(it) && Item_ItemsTime_GetTime(it.m_id) != -1, {
        id = it.m_id;
        icon = it.m_icon;
+               
 
 LABEL(iteration)
         float item_time = Item_ItemsTime_GetTime(id);
@@ -432,6 +479,18 @@ LABEL(iteration)
         if(id == REGISTRY_MAX(Items)) // can happen only in the last fake iteration
                break;
     });
+       
+       // for RJZ
+       if(total_shards != -1) {
+               DrawItemsTimeItemFixed(pos + vec2(column * (itemstime_size.x + offset.x), row * (itemstime_size.y + offset.y) + itemstime_size.y * 0.5), itemstime_size, ar, "gfx/shards.tga", total_shards, '0.16 0.7 0.83');
+               ++row;
+               if (row >= rows)
+               {
+                       row = 0;
+                       column = column + 1;
+               }
+       }
+       
     // add another fake iteration for superweapons time
     if(id < REGISTRY_MAX(Items) && Item_ItemsTime_GetTime(REGISTRY_MAX(Items)) != -1)
     {
index abbb1de483a45239d8dc37f49509569290627042..50a89602fc6bb3b50951ef456a7fe09db4b388d9 100644 (file)
@@ -1,5 +1,9 @@
 #pragma once
 
+#ifdef CSQC
+int total_shards = -1;
+#endif
+
 #ifdef SVQC
 int autocvar_sv_itemstime;
 #endif
index 311e7a73813a1cdfb828c30f1377f44c01a6d8ee..9000bf98815072c3f3b868142bb2027f6e4888f7 100644 (file)
@@ -93,11 +93,13 @@ void W_OverkillNex_Attack(Weapon thiswep, entity actor, .entity weaponentity, fl
        impressive_hits = 0;
        FireRailgunBullet(actor, weaponentity, w_shotorg, w_shotorg + w_shotdir * max_shot_distance, mydmg, true, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, thiswep.m_id);
 
-       if(yoda && flying)
-               Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
+       if(yoda && flying) {
+               Give_Medal(actor, YODA);
+       }
+               
        if(impressive_hits && actor.oknex_lasthit)
        {
-               Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_IMPRESSIVE);
+               Give_Medal(actor, IMPRESSIVE);
                impressive_hits = 0; // only every second time
        }
 
@@ -266,7 +268,7 @@ METHOD(OverkillNex, wr_think, void(entity thiswep, entity actor, .entity weapone
 
 METHOD(OverkillNex, wr_setup, void(entity thiswep, entity actor, .entity weaponentity))
 {
-       actor.oknex_lasthit = 0;
+       //actor.oknex_lasthit = 0;
 }
 
 METHOD(OverkillNex, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
index f9e40965b8473282a398fdcedd9dd29c462b8532..1413981c6938abc71ba1f6bfa999608456ba1575 100644 (file)
@@ -9,6 +9,10 @@ REGISTER_NET_TEMP(TE_CSQC_SERVERWELCOME)
 REGISTER_NET_TEMP(TE_CSQC_VEHICLESETUP)
 REGISTER_NET_TEMP(TE_CSQC_WEAPONPICKUP)
 
+REGISTER_NET_TEMP(TE_CSQC_TEAMNAMES)
+REGISTER_NET_TEMP(TE_CSQC_CHATSOUND)
+REGISTER_NET_TEMP(TE_CSQC_TOTALSHARDS) // for RJZ
+
 const int RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder
 const int RACE_NET_CHECKPOINT_CLEAR = 1;
 const int RACE_NET_CHECKPOINT_NEXT_QUALIFYING = 2; // byte nextcheckpoint, short recordtime, string recordholder
index dc118fac66617e6333ad52212fa16db7fe2557d4..2adf9371ed7c919a0f2c3de1daca08bf3b8ab9b2 100644 (file)
@@ -97,6 +97,7 @@
 #define N___NEVER 0
 #define N_GNTLOFF 1
 #define N__ALWAYS 2
+#define ANNCE_DEFTIME 2
 
 // default time for announcer queue (time to wait before the next announcer is played)
 // -1 = bypass queue and play the announcer immediately
 #define ANNCE_LENGTH 0
 #define ANNCE_DEFTIME 2
 
-#define MULTITEAM_ANNCE(prefix, defaultvalue, sound, channel, volume, position) \
+#define MULTITEAM_ANNCE(prefix, defaultvalue, sound, channel, volume, position, queuetime) \
     NOTIF_ADD_AUTOCVAR(ANNCE_##prefix, defaultvalue) \
-    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_1, prefix##_RED, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_1)), channel, volume, position) \
-    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_2, prefix##_BLUE, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_2)), channel, volume, position) \
-    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_3, prefix##_YELLOW, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_3)), channel, volume, position) \
-    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_4, prefix##_PINK, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_4)), channel, volume, position)
+    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_1, prefix##_RED, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_1)), channel, volume, position, queuetime) \
+    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_2, prefix##_BLUE, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_2)), channel, volume, position, queuetime) \
+    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_3, prefix##_YELLOW, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_3)), channel, volume, position, queuetime) \
+    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_4, prefix##_PINK, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_4)), channel, volume, position, queuetime)
 
 // MSG_ANNCE_NOTIFICATIONS
     MSG_ANNCE_NOTIF(ACHIEVEMENT_AIRSHOT,        N_GNTLOFF, "airshot",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(ACHIEVEMENT_AMAZING,        N_GNTLOFF, "amazing",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
-    MSG_ANNCE_NOTIF(ACHIEVEMENT_AWESOME,        N_GNTLOFF, "awesome",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(ACHIEVEMENT_ASSIST,         N_GNTLOFF, "assist",            CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(ACHIEVEMENT_AWESOME,        N_GNTLOFF, "awesome",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(ACHIEVEMENT_DAMAGE,         N_GNTLOFF, "damage",            CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(ACHIEVEMENT_DEFENSE,        N_GNTLOFF, "defense",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(ACHIEVEMENT_EXCELLENT,      N_GNTLOFF, "excellent",         CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(ACHIEVEMENT_BOTLIKE,        N_GNTLOFF, "botlike",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(ACHIEVEMENT_ELECTROBITCH,   N__ALWAYS, "electrobitch",      CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(ACHIEVEMENT_IMPRESSIVE,     N_GNTLOFF, "impressive",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(ACHIEVEMENT_YODA,           N_GNTLOFF, "yoda",              CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(ACHIEVEMENT_PERFECT,        N_GNTLOFF, "perfect",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(ACHIEVEMENT_ACCURACY,       N_GNTLOFF, "accuracy",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(ACHIEVEMENT_TELEFRAG,       N_GNTLOFF, "telefrag",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 
-    MSG_ANNCE_NOTIF(BEGIN,                      N__ALWAYS, "begin",             CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
+    MSG_ANNCE_NOTIF(BEGIN,                      N__ALWAYS, "begin",             CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 
     MSG_ANNCE_NOTIF(HEADSHOT,                   N__ALWAYS, "headshot",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(HUMILIATION,                N__ALWAYS, "humiliation",       CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 
     MSG_ANNCE_NOTIF(KILLSTREAK_03,              N_GNTLOFF, "03kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(KILLSTREAK_05,              N_GNTLOFF, "05kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(KILLSTREAK_10,              N_GNTLOFF, "10kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(KILLSTREAK_15,              N_GNTLOFF, "15kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
-    MSG_ANNCE_NOTIF(KILLSTREAK_20,              N_GNTLOFF, "20kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
-    MSG_ANNCE_NOTIF(KILLSTREAK_25,              N_GNTLOFF, "25kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
-    MSG_ANNCE_NOTIF(KILLSTREAK_30,              N_GNTLOFF, "30kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 
     MSG_ANNCE_NOTIF(INSTAGIB_LASTSECOND,        N_GNTLOFF, "lastsecond",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(INSTAGIB_NARROWLY,          N_GNTLOFF, "narrowly",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(INSTAGIB_TERMINATED,        N_GNTLOFF, "terminated",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 
-    MSG_ANNCE_NOTIF(MULTIFRAG,                  N___NEVER, "multifrag",         CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
-
-    MSG_ANNCE_NOTIF(NUM_1,                      N__ALWAYS, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_2,                      N__ALWAYS, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_3,                      N__ALWAYS, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_4,                      N__ALWAYS, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_5,                      N__ALWAYS, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_6,                      N__ALWAYS, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_7,                      N__ALWAYS, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_8,                      N__ALWAYS, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_9,                      N__ALWAYS, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_10,                     N__ALWAYS, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-
-    MSG_ANNCE_NOTIF(NUM_GAMESTART_1,            N__ALWAYS, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_GAMESTART_2,            N__ALWAYS, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_GAMESTART_3,            N__ALWAYS, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_GAMESTART_4,            N__ALWAYS, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_GAMESTART_5,            N__ALWAYS, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_GAMESTART_6,            N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_GAMESTART_7,            N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_GAMESTART_8,            N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_GAMESTART_9,            N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_GAMESTART_10,           N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-
-    MSG_ANNCE_NOTIF(NUM_KILL_1,                 N___NEVER, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_KILL_2,                 N___NEVER, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_KILL_3,                 N___NEVER, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_KILL_4,                 N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_KILL_5,                 N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_KILL_6,                 N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_KILL_7,                 N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_KILL_8,                 N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_KILL_9,                 N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_KILL_10,                N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-
-    MSG_ANNCE_NOTIF(NUM_RESPAWN_1,              N___NEVER, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_RESPAWN_2,              N___NEVER, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_RESPAWN_3,              N___NEVER, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_RESPAWN_4,              N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_RESPAWN_5,              N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_RESPAWN_6,              N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_RESPAWN_7,              N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_RESPAWN_8,              N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_RESPAWN_9,              N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_RESPAWN_10,             N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-
-    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_1,           N__ALWAYS, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_2,           N__ALWAYS, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_3,           N__ALWAYS, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_4,           N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_5,           N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_6,           N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_7,           N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_8,           N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_9,           N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_10,          N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
-
-    MSG_ANNCE_NOTIF(PREPARE,                    N__ALWAYS, "prepareforbattle",  CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+    MSG_ANNCE_NOTIF(MULTIFRAG,                  N_GNTLOFF, "multifrag",         CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(FIRSTBLOOD,                 N_GNTLOFF, "firstblood",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+
+    MSG_ANNCE_NOTIF(NUM_1,                      N__ALWAYS, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_2,                      N__ALWAYS, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_3,                      N__ALWAYS, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_4,                      N__ALWAYS, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_5,                      N__ALWAYS, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_6,                      N__ALWAYS, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_7,                      N__ALWAYS, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_8,                      N__ALWAYS, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_9,                      N__ALWAYS, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_10,                     N__ALWAYS, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+
+    MSG_ANNCE_NOTIF(NUM_GAMESTART_1,            N__ALWAYS, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_GAMESTART_2,            N__ALWAYS, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_GAMESTART_3,            N__ALWAYS, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_GAMESTART_4,            N__ALWAYS, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_GAMESTART_5,            N__ALWAYS, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_GAMESTART_6,            N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_GAMESTART_7,            N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_GAMESTART_8,            N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_GAMESTART_9,            N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_GAMESTART_10,           N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+
+    MSG_ANNCE_NOTIF(NUM_IDLE_1,                 N___NEVER, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_IDLE_2,                 N___NEVER, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_IDLE_3,                 N___NEVER, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_IDLE_4,                 N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_IDLE_5,                 N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_IDLE_6,                 N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_IDLE_7,                 N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_IDLE_8,                 N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_IDLE_9,                 N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_IDLE_10,                N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+
+    MSG_ANNCE_NOTIF(NUM_KILL_1,                 N___NEVER, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_KILL_2,                 N___NEVER, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_KILL_3,                 N___NEVER, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_KILL_4,                 N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_KILL_5,                 N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_KILL_6,                 N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_KILL_7,                 N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_KILL_8,                 N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_KILL_9,                 N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_KILL_10,                N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+
+    MSG_ANNCE_NOTIF(NUM_RESPAWN_1,              N___NEVER, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_RESPAWN_2,              N___NEVER, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_RESPAWN_3,              N___NEVER, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_RESPAWN_4,              N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_RESPAWN_5,              N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_RESPAWN_6,              N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_RESPAWN_7,              N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_RESPAWN_8,              N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_RESPAWN_9,              N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_RESPAWN_10,             N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+
+    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_1,           N__ALWAYS, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_2,           N__ALWAYS, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_3,           N__ALWAYS, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_4,           N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_5,           N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_6,           N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_7,           N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_8,           N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_9,           N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_10,          N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+
+    MSG_ANNCE_NOTIF(PREPARE,                    N__ALWAYS, "prepareforbattle",  CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+       MSG_ANNCE_NOTIF(PREPARE_TEAM,               N__ALWAYS, "prepareyourteam",   CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 
     MSG_ANNCE_NOTIF(REMAINING_FRAG_1,           N_GNTLOFF, "1fragleft",         CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(REMAINING_FRAG_2,           N_GNTLOFF, "2fragsleft",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(REMAINING_MIN_1,            N__ALWAYS, "1minuteremains",    CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(REMAINING_MIN_5,            N__ALWAYS, "5minutesremain",    CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 
-    MSG_ANNCE_NOTIF(TIMEOUT,                    N__ALWAYS, "timeoutcalled",     CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
+    MSG_ANNCE_NOTIF(TIMEOUT,                    N__ALWAYS, "timeoutcalled",     CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+       MSG_ANNCE_NOTIF(OVERTIME,                   N__ALWAYS, "overtime",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(SUDDENDEATH,                N__ALWAYS, "suddendeath",       CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(SUICIDE,                    N_GNTLOFF, "suicide",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
+       MSG_ANNCE_NOTIF(ACCIDENT,                   N_GNTLOFF, "accident",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 
     MSG_ANNCE_NOTIF(VOTE_ACCEPT,                N__ALWAYS, "voteaccept",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(VOTE_CALL,                  N__ALWAYS, "votecall",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(VOTE_FAIL,                  N__ALWAYS, "votefail",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       
+       MSG_ANNCE_NOTIF(LEAD_GAINED,                N__ALWAYS, "leadgained",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(LEAD_LOST,                  N__ALWAYS, "leadlost",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(LEAD_TIED,                  N__ALWAYS, "leadtied",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       
+       MULTITEAM_ANNCE(ROUND_TEAM_WIN,                         N__ALWAYS, "round_win_%s",              CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       
+       MSG_ANNCE_NOTIF(TEAM_SCORES_TEAM,                       N__ALWAYS, "scores_team",               CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(TEAM_SCORES_ENEMY,                      N__ALWAYS, "scores_enemy",              CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MULTITEAM_ANNCE(TEAM_SCORES,                            N__ALWAYS, "scores_%s",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       
+       MSG_ANNCE_NOTIF(TEAM_LEADS_TEAM,                        N__ALWAYS, "leads_team",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(TEAM_LEADS_ENEMY,                       N__ALWAYS, "leads_enemy",               CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MULTITEAM_ANNCE(TEAM_LEADS,                                     N__ALWAYS, "leads_%s",                  CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       
+       MULTITEAM_ANNCE(TEAM_WINS,                                      N__ALWAYS, "wins_%s",                   CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       
+       MSG_ANNCE_NOTIF(TEAM_LEADS_TIED,            N__ALWAYS, "teamstied",         CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(ROUND_OVER,                 N__ALWAYS, "round_over",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(ROUND_TIED,                 N__ALWAYS, "round_tied",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(ALONE,                      N__ALWAYS, "alone",             CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       
+       MSG_ANNCE_NOTIF(CTF_PICKUP_YOU,             N__ALWAYS, "ctf_pickup_you",    CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(CTF_PICKUP_TEAM,            N__ALWAYS, "ctf_pickup_team",   CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(CTF_PICKUP_ENEMY,           N__ALWAYS, "ctf_pickup_enemy",  CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MULTITEAM_ANNCE(CTF_PICKUP,                                     N__ALWAYS, "ctf_pickup_%s",             CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       
+       MSG_ANNCE_NOTIF(CTF_RETURN_TEAM,            N__ALWAYS, "ctf_return_team",   CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MSG_ANNCE_NOTIF(CTF_RETURN_ENEMY,           N__ALWAYS, "ctf_return_enemy",  CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+       MULTITEAM_ANNCE(CTF_RETURN,                                     N__ALWAYS, "ctf_return_%s",             CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+
+// MSG_MEDAL_NOTIFICATIONS
+
+#define MSG_MEDAL_TIME 2
+#define MSG_MEDAL_FADE_TIME 0.5
+
+       MSG_MEDAL_NOTIF(AIRSHOT, N__ALWAYS,        "airshot",       ANNCE_ACHIEVEMENT_AIRSHOT)
+       MSG_MEDAL_NOTIF(ASSIST, N__ALWAYS,         "assist",        ANNCE_ACHIEVEMENT_ASSIST)
+       MSG_MEDAL_NOTIF(DAMAGE, N__ALWAYS,         "damage",        ANNCE_ACHIEVEMENT_DAMAGE)
+       MSG_MEDAL_NOTIF(DEFENSE, N__ALWAYS,        "defense",       ANNCE_ACHIEVEMENT_DEFENSE)
+       MSG_MEDAL_NOTIF(ELECTROBITCH, N__ALWAYS,   "electrobitch",  ANNCE_ACHIEVEMENT_ELECTROBITCH)
+       MSG_MEDAL_NOTIF(EXCELLENT, N__ALWAYS,      "excellent",     ANNCE_ACHIEVEMENT_EXCELLENT)
+       MSG_MEDAL_NOTIF(FIRSTBLOOD, N__ALWAYS,     "firstblood",    ANNCE_FIRSTBLOOD)
+       MSG_MEDAL_NOTIF(HEADSHOT, N__ALWAYS,       "headshot",      ANNCE_HEADSHOT)
+       MSG_MEDAL_NOTIF(HUMILIATION, N__ALWAYS,    "humiliation",   ANNCE_HUMILIATION)
+       MSG_MEDAL_NOTIF(IMPRESSIVE, N__ALWAYS,     "impressive",    ANNCE_ACHIEVEMENT_IMPRESSIVE)
+       MSG_MEDAL_NOTIF(YODA, N__ALWAYS,           "yoda",          ANNCE_ACHIEVEMENT_YODA)
+       MSG_MEDAL_NOTIF(TELEFRAG, N__ALWAYS,       "telefrag",      ANNCE_ACHIEVEMENT_TELEFRAG)
+       
+       MSG_MEDAL_NOTIF(CAPTURE, N__ALWAYS,        "capture",       NULL)
+       MSG_MEDAL_NOTIF(PERFECT, N__ALWAYS,        "perfect",       ANNCE_ACHIEVEMENT_PERFECT)
+       MSG_MEDAL_NOTIF(ACCURACY, N__ALWAYS,       "accuracy",      ANNCE_ACHIEVEMENT_ACCURACY)
+       
+       MSG_MEDAL_NOTIF(KILLSTREAK_03, N__ALWAYS, "killstreak_03", ANNCE_KILLSTREAK_03)
+       MSG_MEDAL_NOTIF(KILLSTREAK_05, N__ALWAYS, "killstreak_05", ANNCE_KILLSTREAK_05)
+       MSG_MEDAL_NOTIF(KILLSTREAK_10, N__ALWAYS, "killstreak_10", ANNCE_KILLSTREAK_10)
+       MSG_MEDAL_NOTIF(KILLSTREAK_15, N__ALWAYS, "killstreak_15", ANNCE_KILLSTREAK_15)
+       
 
 #undef N___NEVER
 #undef N_GNTLOFF
@@ -370,6 +451,7 @@ string multiteam_info_sprintf(string input, string teamname) { return ((input !=
     MSG_INFO_NOTIF(FREEZETAG_SELF,                          N_CONSOLE,  1, 0, "s1", "",         "",     _("^BG%s^K1 froze themself"), "")
 
     MULTITEAM_INFO(ROUND_TEAM_WIN,                          N_CONSOLE,  0, 0, "", "",           "",     _("^TC^TT^BG team wins the round"), "", NAME)
+       MULTITEAM_INFO(ROUND_TEAM_SCORES,                       N_CONSOLE,  0, 0, "", "",           "",     _("^TC^TT^BG scores"), "", NAME)
     MSG_INFO_NOTIF(ROUND_PLAYER_WIN,                        N_CONSOLE,  1, 0, "s1", "",         "",     _("^BG%s^BG wins the round"), "")
     MSG_INFO_NOTIF(ROUND_TIED,                              N_CONSOLE,  0, 0, "", "",           "",     _("^BGRound tied"), "")
     MSG_INFO_NOTIF(ROUND_OVER,                              N_CONSOLE,  0, 0, "", "",           "",     _("^BGRound over, there's no winner"), "")
@@ -392,6 +474,7 @@ string multiteam_info_sprintf(string input, string teamname) { return ((input !=
     MSG_INFO_NOTIF(JOIN_CONNECT,                            N_CHATCON,  1, 0, "s1", "",         "",     _("^BG%s^F3 connected"), "")
     MSG_INFO_NOTIF(JOIN_PLAY,                               N_CHATCON,  1, 0, "s1", "",         "",     _("^BG%s^F3 is now playing"), "")
     MULTITEAM_INFO(JOIN_PLAY_TEAM,                          N_CHATCON,  1, 0, "s1", "",         "",     _("^BG%s^F3 is now playing on the ^TC^TT team"), "", NAME)
+    MULTITEAM_INFO(JOIN_WANTS_TEAM,                         N_CHATCON,  1, 0, "s1", "",         "",     _("^BG%s^F3 wants to play on the ^TC^TT team"), "", NAME)
 
     MSG_INFO_NOTIF(KEEPAWAY_DROPPED,                        N_CONSOLE,  1, 0, "s1", "s1",       "notify_balldropped",       _("^BG%s^BG has dropped the ball!"), "")
     MSG_INFO_NOTIF(KEEPAWAY_PICKUP,                         N_CONSOLE,  1, 0, "s1", "s1",       "notify_ballpickedup",      _("^BG%s^BG has picked up the ball!"), "")
@@ -422,12 +505,15 @@ string multiteam_info_sprintf(string input, string teamname) { return ((input !=
     MSG_INFO_NOTIF(POWERUP_STRENGTH,                        N_CONSOLE,  1, 0, "s1", "s1",       "strength",       _("^BG%s^K1 picked up Strength"), "")
 
     MSG_INFO_NOTIF(QUIT_DISCONNECT,                         N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 disconnected"), "")
+    MSG_INFO_NOTIF(QUIT_KICK,                               N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 was kicked"), "")
     MSG_INFO_NOTIF(QUIT_KICK_IDLING,                        N_CHATCON,  1, 1, "s1 f1", "",      "",             _("^BG%s^F3 was kicked after idling for %s seconds"), "")
     MSG_INFO_NOTIF(MOVETOSPEC_IDLING,                       N_CHATCON,  1, 1, "s1 f1", "",      "",             _("^BG%s^F3 was moved to^BG spectators^F3 after idling for %s seconds"), "")
+    MSG_INFO_NOTIF(MOVETOSPEC_REMOVE,                       N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 was moved to^BG spectators^F3 for balance reasons"), "")
     MSG_INFO_NOTIF(QUIT_KICK_SPECTATING,                    N_CONSOLE,  0, 0, "", "",           "",             _("^F2You were kicked from the server because you are a spectator and spectators aren't allowed at the moment."), "")
     MSG_INFO_NOTIF(QUIT_KICK_TEAMKILL,                      N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 was kicked for excessive teamkilling"), "")
     MSG_INFO_NOTIF(QUIT_PLAYBAN_TEAMKILL,                   N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 was forced to spectate for excessive teamkilling"), "")
     MSG_INFO_NOTIF(QUIT_SPECTATE,                           N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 is now^BG spectating"), "")
+    MSG_INFO_NOTIF(QUIT_QUEUE,                              N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 has left the queue"), "")
 
     MSG_INFO_NOTIF(RACE_ABANDONED,                          N_CONSOLE,  1, 0, "s1", "",                                                                     "",                         _("^BG%s^BG has abandoned the race"), "")
     MSG_INFO_NOTIF(RACE_FAIL_RANKED,                        N_CONSOLE,  1, 3, "s1 race_col f1ord race_col f3race_time race_diff", "s1 f3race_time",         "race_newfail",             _("^BG%s^BG couldn't break their %s%s^BG place record of %s%s %s"), "")
@@ -597,11 +683,15 @@ string multiteam_info_sprintf(string input, string teamname) { return ((input !=
 
     #define VERBOSE_MURDER(type) strcat(MURDER_##type, "^BG%s")
 
-    #define MURDER_FRAG             BOLD(_("^K3%sYou fragged ^BG%s"))
-    #define MURDER_FRAG2            BOLD(_("^K3%sYou scored against ^BG%s"))
-    #define MURDER_FRAGGED          BOLD(_("^K1%sYou were fragged by ^BG%s"))
-    #define MURDER_FRAGGED2         BOLD(_("^K1%sYou were scored against by ^BG%s"))
+    #define MURDER_FRAG             strcat(BOLD_OPERATOR, _("^K3%sYou fragged ^BG%s"))
+    #define MURDER_FRAG2            strcat(BOLD_OPERATOR, _("^K3%sYou scored against ^BG%s"))
+       #define MURDER_FRAG3            strcat(BOLD_OPERATOR, _("^K3%sYou fragged ^BG%s"), "\n", "%s^BG place with %s")
+       #define MURDER_FRAG4            strcat(BOLD_OPERATOR, _("^K3%sYou fragged ^BG%s"), "\n", "%s^BG with %s")
+    #define MURDER_FRAGGED          _("^K1%sYou were fragged by ^BG%s")
+    #define MURDER_FRAGGED2         _("^K1%sYou were scored against by ^BG%s")
     MSG_CENTER_NOTIF(DEATH_MURDER_FRAG,                   N_ENABLE,  1, 1, "spree_cen s1",               CPID_Null,  "0 0",  MURDER_FRAG,                    MURDER_FRAG2                   )
+       MSG_CENTER_NOTIF(DEATH_MURDER_DM,                     N_ENABLE,  1, 2, "spree_cen s1 frag_pos f2",   CPID_Null,  "0 0",  MURDER_FRAG3, "")
+       MSG_CENTER_NOTIF(DEATH_MURDER_DUEL,                   N_ENABLE,  2, 2, "spree_cen s1 s2 f2",         CPID_Null,  "0 0",  MURDER_FRAG4, "")
     MSG_CENTER_NOTIF(DEATH_MURDER_FRAGGED,                N_ENABLE,  1, 1, "spree_cen s1",               CPID_Null,  "0 0",  MURDER_FRAGGED,                 MURDER_FRAGGED2                )
     MSG_CENTER_NOTIF(DEATH_MURDER_FRAGGED_VERBOSE,        N_ENABLE,  1, 4, "spree_cen s1 frag_stats",    CPID_Null,  "0 0",  VERBOSE_MURDER(FRAGGED),        VERBOSE_MURDER(FRAGGED2)       )
     MSG_CENTER_NOTIF(DEATH_MURDER_FRAG_VERBOSE,           N_ENABLE,  1, 2, "spree_cen s1 frag_ping",     CPID_Null,  "0 0",  VERBOSE_MURDER(FRAG),           VERBOSE_MURDER(FRAG2)          )
@@ -677,6 +767,7 @@ string multiteam_info_sprintf(string input, string teamname) { return ((input !=
 
     MSG_CENTER_NOTIF(DISCONNECT_IDLING,                 N_ENABLE,    0, 1, "",               CPID_IDLING,            "1 f1", BOLD(_("^K1Stop idling!\n^BGDisconnecting in ^COUNT...")), "")
     MSG_CENTER_NOTIF(MOVETOSPEC_IDLING,                 N_ENABLE,    0, 1, "",               CPID_IDLING,            "1 f1", BOLD(_("^K1Stop idling!\n^BGMoving to spectators in ^COUNT...")), "")
+    MSG_CENTER_NOTIF(MOVETOSPEC_REMOVE,                 N_ENABLE,    1, 1, "s1",             CPID_REMOVE,            "1 f1", BOLD(_("^K1Teams unbalanced!\n^BGMoving %s^BG to spectators in ^COUNT...")), "")
 
     MSG_CENTER_NOTIF(DOOR_LOCKED_NEED,                  N_ENABLE,    1, 0, "s1",             CPID_Null,              "0 0",  _("^BGYou need %s^BG!"), "")
     MSG_CENTER_NOTIF(DOOR_LOCKED_ALSONEED,              N_ENABLE,    1, 0, "s1",             CPID_Null,              "0 0",  _("^BGYou also need %s^BG!"), "")
@@ -693,6 +784,7 @@ string multiteam_info_sprintf(string input, string teamname) { return ((input !=
 
     MULTITEAM_CENTER(ROUND_TEAM_LOSS,                   N_ENABLE,    0, 0, "",               CPID_ROUND,             "0 0",  _("^TC^TT^BG team loses the round"), "", NAME)
     MULTITEAM_CENTER(ROUND_TEAM_WIN,                    N_ENABLE,    0, 0, "",               CPID_ROUND,             "0 0",  _("^TC^TT^BG team wins the round"), "", NAME)
+       MULTITEAM_CENTER(ROUND_TEAM_SCORES,                 N_ENABLE,    0, 0, "",               CPID_ROUND,             "0 0",  _("^TC^TT^BG scores"), "", NAME)
     MSG_CENTER_NOTIF(ROUND_PLAYER_WIN,                  N_ENABLE,    1, 0, "s1",             CPID_ROUND,             "0 0",  _("^BG%s^BG wins the round"), "")
 
     MSG_CENTER_NOTIF(FREEZETAG_SELF,                    N_ENABLE,    0, 0, "",               CPID_Null,              "0 0",  _("^K1You froze yourself"), "")
@@ -715,6 +807,7 @@ string multiteam_info_sprintf(string input, string teamname) { return ((input !=
     MSG_CENTER_NOTIF(JOIN_PLAYBAN,                      N_ENABLE,    0, 0, "",               CPID_PREVENT_JOIN,      "0 0",  BOLD(_("^K1You aren't allowed to play because you are banned in this server")), "")
     MSG_CENTER_NOTIF(JOIN_PREVENT,                      N_ENABLE,    0, 1, "f1",             CPID_PREVENT_JOIN,      "0 0",  _("^K1You may not join the game at this time.\nThis match is limited to ^F2%s^BG players."), "")
     MSG_CENTER_NOTIF(JOIN_PREVENT_MINIGAME,             N_ENABLE,    0, 0, "",               CPID_Null,              "0 0",  _("^K1Cannot join given minigame session!"), "" )
+    MSG_CENTER_NOTIF(JOIN_PREVENT_QUEUE,                N_ENABLE,    0, 0, "",               CPID_Null,              "0 0",  _("^BGYou are now queued to join the game."), "")
 
     MSG_CENTER_NOTIF(KEEPAWAY_DROPPED,                  N_ENABLE,    1, 0, "s1",             CPID_KEEPAWAY,          "0 0",  _("^BG%s^BG has dropped the ball!"), "")
     MSG_CENTER_NOTIF(KEEPAWAY_PICKUP,                   N_ENABLE,    1, 0, "s1",             CPID_KEEPAWAY,          "0 0",  _("^BG%s^BG has picked up the ball!"), "")
@@ -734,6 +827,7 @@ string multiteam_info_sprintf(string input, string teamname) { return ((input !=
 
     MSG_CENTER_NOTIF(MISSING_TEAMS,                     N_ENABLE,    0, 1, "missing_teams",  CPID_MISSING_TEAMS,     "-1 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "")
     MSG_CENTER_NOTIF(MISSING_PLAYERS,                   N_ENABLE,    0, 1, "f1",             CPID_MISSING_PLAYERS,   "-1 0", _("^BGWaiting for %s player(s) to join..."), "")
+       MSG_CENTER_NOTIF(MISSING_READY,                     N_ENABLE,    0, 0, "",               CPID_MISSING_READY,     "-1 0", _("^BGThe match will begin\nwhen more players are ready.\n\nPress ^F2F4^BG to get ready"), "")
 
     MSG_CENTER_NOTIF(INSTAGIB_DOWNGRADE,                N_ENABLE,    0, 0, "",               CPID_INSTAGIB_FINDAMMO, "5 0",  _("^BGYour weapon has been downgraded until you find some ammo!"), "")
     MSG_CENTER_NOTIF(INSTAGIB_FINDAMMO,                 N_ENABLE,    0, 0, "",               CPID_INSTAGIB_FINDAMMO, "1 9",  _("^F4^COUNT^BG left to find some ammo!"), "")
@@ -798,6 +892,7 @@ string multiteam_info_sprintf(string input, string teamname) { return ((input !=
 
     MSG_CENTER_NOTIF(TIMEOUT_BEGINNING,                 N_ENABLE,    0, 1, "",               CPID_TIMEOUT,           "1 f1", _("^F4Timeout begins in ^COUNT"), "")
     MSG_CENTER_NOTIF(TIMEOUT_ENDING,                    N_ENABLE,    0, 1, "",               CPID_TIMEIN,            "1 f1", _("^F4Timeout ends in ^COUNT"), "")
+       MSG_CENTER_NOTIF(TIMEOUT_ONGOING,                   N_ENABLE,    0, 0, "",               CPID_TIMEIN,            "1 f1", _("^F4Match paused"), "")
 
     MSG_CENTER_NOTIF(VEHICLE_ENTER,                     N_ENABLE,    0, 0, "pass_key",       CPID_VEHICLES,          "0 0",  _("^BGPress ^F2%s^BG to enter/exit the vehicle"), "")
     MSG_CENTER_NOTIF(VEHICLE_ENTER_GUNNER,              N_ENABLE,    0, 0, "pass_key",       CPID_VEHICLES,          "0 0",  _("^BGPress ^F2%s^BG to enter the vehicle gunner"), "")
index dd200973bc007804c28258c12343b02130d6ec55..82c14207284c844d9a327e9de5411eb47a3a8350 100644 (file)
@@ -41,6 +41,7 @@ string Notification_CheckArgs(
                        break;
                }
 
+               case NOTIF_ALL_SPEC:
                case NOTIF_ALL:
                {
                        if (client) {
@@ -50,6 +51,7 @@ string Notification_CheckArgs(
                }
 
                case NOTIF_TEAM:
+               case NOTIF_TEAM_ONLY:
                {
                        if (!teamplay) {
                                return "Teamplay not active!";
@@ -60,6 +62,7 @@ string Notification_CheckArgs(
                }
 
                case NOTIF_TEAM_EXCEPT:
+               case NOTIF_TEAM_ONLY_EXCEPT:
                {
                        if (!teamplay) {
                                return "Teamplay not active!";
@@ -120,6 +123,20 @@ bool Notification_ShouldSend(NOTIF broadcast, entity to_client, entity other_cli
                                        )
                                )
                        );
+               case NOTIF_TEAM_ONLY:
+                       return (
+                               (to_client.team == other_client.team)
+                       );
+               case NOTIF_TEAM_ONLY_EXCEPT:
+                       return (
+                               (to_client != other_client)
+                               &&
+                               (to_client.team == other_client.team)
+                       );
+               case NOTIF_ALL_SPEC:
+                       return (
+                               (IS_SPEC(to_client) || IS_OBSERVER(to_client))
+                       );
                case NOTIF_ALL:
                        return true;
                case NOTIF_ALL_EXCEPT:
@@ -419,6 +436,7 @@ void Create_Notification_Entity(entity notif,
                case MSG_CENTER:
                case MSG_MULTI:
                case MSG_CHOICE:
+               case MSG_MEDAL:
                        break;
                default:
                        LOG_INFOF(
@@ -757,6 +775,17 @@ void Create_Notification_Entity_Choice(entity notif,
                        }
                }
 
+void Create_Notification_Entity_Medal(entity notif,
+                                                                               float var_cvar,
+                                                                               string namestring,
+                                                                               /* MSG_MEDAL */
+                                                                               string icon,
+                                                                               Notification anncename)
+       {
+               notif.nent_floatcount = 1;
+               if (icon != "") { notif.nent_icon = strzone(icon); }
+               if (anncename) { notif.nent_msgannce = anncename; }
+       }
 
 // ===============
 //  Cvar Handling
@@ -829,6 +858,7 @@ void Dump_Notifications(int fh, bool alsoprint)
        int NOTIF_CENTER_COUNT = 0;
        int NOTIF_MULTI_COUNT = 0;
        int NOTIF_CHOICE_COUNT = 0;
+       int NOTIF_MEDAL_COUNT = 0;
        FOREACH(Notifications, true, {
                switch (it.nent_type)
                {
@@ -837,6 +867,7 @@ void Dump_Notifications(int fh, bool alsoprint)
                        case MSG_CENTER: ++NOTIF_CENTER_COUNT; break;
                        case MSG_MULTI: ++NOTIF_MULTI_COUNT; break;
                        case MSG_CHOICE: ++NOTIF_CHOICE_COUNT; break;
+                       case MSG_MEDAL: ++NOTIF_MEDAL_COUNT; break;
                }
        });
 
@@ -876,6 +907,13 @@ void Dump_Notifications(int fh, bool alsoprint)
                        "Allow choice for this notification 0 = off, 1 = only in warmup mode, 2 = always"
                );
        });
+       
+       NOTIF_WRITE(sprintf("\n// MSG_MEDAL notifications (count = %d):\n", NOTIF_MEDAL_COUNT));
+       FOREACH(Notifications, it.nent_type == MSG_MEDAL && (!it.nent_teamnum || it.nent_teamnum == NUM_TEAM_1), {
+               NOTIF_WRITE_ENTITY(it,
+                       "Enable this multiple notification"
+               );
+       });
 
        // edit these to match whichever cvars are used for specific notification options
        NOTIF_WRITE("\n// HARD CODED notification variables:\n");
@@ -971,13 +1009,15 @@ void Dump_Notifications(int fh, bool alsoprint)
                        NOTIF_INFO_COUNT +
                        NOTIF_CENTER_COUNT +
                        NOTIF_MULTI_COUNT +
-                       NOTIF_CHOICE_COUNT
+                       NOTIF_CHOICE_COUNT +
+                       NOTIF_MEDAL_COUNT
                ),
                NOTIF_ANNCE_COUNT,
                NOTIF_INFO_COUNT,
                NOTIF_CENTER_COUNT,
                NOTIF_MULTI_COUNT,
-               NOTIF_CHOICE_COUNT
+               NOTIF_CHOICE_COUNT,
+               NOTIF_MEDAL_COUNT
        );
        #undef NOTIF_WRITE_HARDCODED
        #undef NOTIF_WRITE_ENTITY
@@ -1180,8 +1220,8 @@ void Local_Notification_centerprint_Add(
        centerprint_Add(ORDINAL(cpid), input, stof(arg_slot[0]), stof(arg_slot[1]));
 }
 
-void Local_Notification_Queue_Run(MSG net_type, entity notif)
-{
+void Local_Notification_Queue_Run(MSG net_type, entity notif, float f1)
+{              
        switch (net_type)
        {
                case MSG_ANNCE:
@@ -1189,18 +1229,30 @@ void Local_Notification_Queue_Run(MSG net_type, entity notif)
                        Local_Notification_sound(notif.nent_channel, notif.nent_snd, notif.nent_vol, notif.nent_position);
                        break;
                }
+               
+               case MSG_MEDAL:
+               {
+                       centerprint_Medal(notif.nent_icon, f1);
+                       if(notif.nent_msgannce)
+                               Local_Notification_sound(
+                                       notif.nent_msgannce.nent_channel,
+                                       notif.nent_msgannce.nent_snd,
+                                       notif.nent_msgannce.nent_vol,
+                                       notif.nent_msgannce.nent_position);
+                       break;
+               }
        }
 }
 
-void Local_Notification_Queue_Add(MSG net_type, entity notif, float queue_time)
-{
+void Local_Notification_Queue_Add(MSG net_type, entity notif, float queue_time, float f1)
+{      
        // Guess length if required
        if(queue_time == 0)
                queue_time = soundlength(AnnouncerFilename(notif.nent_snd));
 
        if(queue_time == -1 || time > notif_queue_next_time) {
                // Run immediately
-               Local_Notification_Queue_Run(net_type, notif);
+               Local_Notification_Queue_Run(net_type, notif, f1);
                notif_queue_next_time = time + queue_time;
        } else {
                // Put in queue
@@ -1209,6 +1261,7 @@ void Local_Notification_Queue_Add(MSG net_type, entity notif, float queue_time)
                notif_queue_type[notif_queue_length] = net_type;
                notif_queue_entity[notif_queue_length] = notif;
                notif_queue_time[notif_queue_length] = notif_queue_next_time;
+               notif_queue_f1[notif_queue_length] = f1;
 
                notif_queue_next_time += queue_time;
                ++notif_queue_length;
@@ -1220,7 +1273,7 @@ void Local_Notification_Queue_Process()
        if(!notif_queue_length || notif_queue_time[0] > time)
                return;
 
-       Local_Notification_Queue_Run(notif_queue_type[0], notif_queue_entity[0]);
+       Local_Notification_Queue_Run(notif_queue_type[0], notif_queue_entity[0], notif_queue_f1[0]);
 
        // Shift queue to the left
        --notif_queue_length;
@@ -1228,6 +1281,7 @@ void Local_Notification_Queue_Process()
                notif_queue_type[j] = notif_queue_type[j+1];
                notif_queue_entity[j] = notif_queue_entity[j+1];
                notif_queue_time[j] = notif_queue_time[j+1];
+               notif_queue_f1[j] = notif_queue_f1[j+1];
        }
 }
 
@@ -1303,7 +1357,7 @@ void Local_Notification(MSG net_type, Notification net_name, ...count)
                case MSG_ANNCE:
                {
                        #ifdef CSQC
-                       Local_Notification_Queue_Add(net_type, notif, notif.nent_queuetime);
+                       Local_Notification_Queue_Add(net_type, notif, notif.nent_queuetime, f1);
                        #else
                        backtrace("MSG_ANNCE on server?... Please notify Samual immediately!\n");
                        #endif
@@ -1413,6 +1467,18 @@ void Local_Notification(MSG net_type, Notification net_name, ...count)
                                f1, f2, f3, f4);
                        break;
                }
+               
+               #ifdef CSQC
+               case MSG_MEDAL:
+               {
+                       Local_Notification_Queue_Add(
+                               net_type,
+                               notif,
+                               (notif.nent_msgannce ? MSG_MEDAL_TIME : 0),
+                               f1);
+                       break;
+               }
+               #endif
        }
 }
 
index f4c25968cc2bf3154b7bd2643c4403ad946b0055..91a49eec29a78505b37ec00a70df4341fd35fa17 100644 (file)
@@ -25,6 +25,8 @@ ENUMCLASS(MSG)
        CASE(MSG, CHOICE)
        /** Kill centerprint message @deprecated */
        CASE(MSG, CENTER_KILL)
+       /** Medal notification */
+       CASE(MSG, MEDAL)
 ENUMCLASS_END(MSG)
 
 string Get_Notif_TypeName(MSG net_type)
@@ -36,12 +38,12 @@ string Get_Notif_TypeName(MSG net_type)
                case MSG_CENTER: return "MSG_CENTER";
                case MSG_MULTI: return "MSG_MULTI";
                case MSG_CHOICE: return "MSG_CHOICE";
+               case MSG_MEDAL: return "MSG_MEDAL";
                case MSG_CENTER_KILL: return "MSG_CENTER_KILL";
        }
        LOG_WARNF("Get_Notif_TypeName(%d): Improper net type!", ORDINAL(net_type));
        return "";
 }
-
 ENUMCLASS(CPID)
        CASE(CPID, ASSAULT_ROLE)
        CASE(CPID, ROUND)
@@ -52,6 +54,7 @@ ENUMCLASS(CPID)
        CASE(CPID, STALEMATE)
        CASE(CPID, NADES)
        CASE(CPID, IDLING)
+       CASE(CPID, REMOVE)
        CASE(CPID, ITEM)
        CASE(CPID, PREVENT_JOIN)
        CASE(CPID, KEEPAWAY)
@@ -61,6 +64,7 @@ ENUMCLASS(CPID)
        CASE(CPID, LMS)
        CASE(CPID, MISSING_TEAMS)
        CASE(CPID, MISSING_PLAYERS)
+       CASE(CPID, MISSING_READY)
        CASE(CPID, INSTAGIB_FINDAMMO)
        CASE(CPID, NIX)
        CASE(CPID, ONSLAUGHT)
@@ -159,6 +163,13 @@ void Create_Notification_Entity_Choice(entity notif,
                                                                                Notification optiona,
                                                                                Notification optionb);
 
+void Create_Notification_Entity_Medal(entity notif,
+                                                                               float var_cvar,
+                                                                               string namestring,
+                                                                               /* MSG_MEDAL */
+                                                                               string icon,
+                                                                               Notification anncename);
+
 void Dump_Notifications(int fh, bool alsoprint);
 
 #define DEFAULT_FILENAME "notifications_dump.cfg"
@@ -251,10 +262,16 @@ ENUMCLASS(NOTIF)
        CASE(NOTIF, TEAM)
        /** send only to X team and their spectators, except for Y person and their spectators */
        CASE(NOTIF, TEAM_EXCEPT)
+       /** send only to X team; don't include spectators */
+       CASE(NOTIF, TEAM_ONLY)
+       /** send to team X team except for Y person; don't include spectators */
+       CASE(NOTIF, TEAM_ONLY_EXCEPT)
        /** send to everyone */
        CASE(NOTIF, ALL)
        /** send to everyone except X person and their spectators */
        CASE(NOTIF, ALL_EXCEPT)
+       /** send to all spectators **/
+       CASE(NOTIF, ALL_SPEC)
 ENUMCLASS_END(NOTIF)
 
 string Get_Notif_BroadcastName(NOTIF broadcast)
@@ -263,10 +280,13 @@ string Get_Notif_BroadcastName(NOTIF broadcast)
        {
                case NOTIF_ONE: return "NOTIF_ONE";
                case NOTIF_ONE_ONLY: return "NOTIF_ONE_ONLY";
+               case NOTIF_ALL_SPEC: return "NOTIF_ALL_SPEC";
                case NOTIF_ALL_EXCEPT: return "NOTIF_ALL_EXCEPT";
                case NOTIF_ALL: return "NOTIF_ALL";
                case NOTIF_TEAM: return "NOTIF_TEAM";
                case NOTIF_TEAM_EXCEPT: return "NOTIF_TEAM_EXCEPT";
+               case NOTIF_TEAM_ONLY: return "NOTIF_TEAM_ONLY";
+               case NOTIF_TEAM_ONLY_EXCEPT: return "NOTIF_TEAM_ONLY_EXCEPT";
        }
        LOG_WARNF("Get_Notif_BroadcastName(%d): Improper broadcast!", broadcast);
        return "";
@@ -391,6 +411,7 @@ const int NOTIF_QUEUE_MAX = 10;
 entity notif_queue_entity[NOTIF_QUEUE_MAX];
 MSG notif_queue_type[NOTIF_QUEUE_MAX];
 float notif_queue_time[NOTIF_QUEUE_MAX];
+float notif_queue_f1[NOTIF_QUEUE_MAX];
 
 float notif_queue_next_time;
 int notif_queue_length;
@@ -442,7 +463,7 @@ string BUFF_NAME(int i);
        ARG_CASE(ARG_CS,        "join_key",      getcommandkey(_("jump"), "+jump")) \
        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,        "frag_pos",      notif_arg_frag_pos(f2)) \
        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) : "")) \
@@ -468,11 +489,73 @@ MACRO_END
        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
+// z411 TODO : This actually doesn't work very well.
+// This gets run before the client gets score updates so it works
+// fine when you're playing (because frags get updated first)
+// but it breaks a lot when you're spectating because
+// we sometimes get the new frag info at different times
+// (before or after we run this). A suggested fix would
+// be to do this sorting and comparison in the server.
+string notif_arg_frag_pos(int score)
+{
+       entity pl;
+       int place = 1;
+       string str, color, tail;
+       bool tied = false;
+       
+       for(pl = players.sort_next; pl; pl = pl.sort_next) {
+               if(pl.team == NUM_SPECTATOR) continue;
+               if(pl.(scores(SP_SCORE)) == score) break;
+               ++place;
+       }
+       
+       entity prev = pl.sort_prev;
+       entity next = pl.sort_next;
+       if(prev && prev.(scores(SP_SCORE)) == score) {
+               tied = true;
+               --place; // We're tied always for the best place
+       }
+       if(next && next.(scores(SP_SCORE)) == score) {
+               tied = true;
+       }
+       
+       switch(place) {
+               case 1:
+                       color = "^4";
+                       break;
+               case 2:
+                       color = "^1";
+                       break;
+               case 3:
+                       color = "^3";
+                       break;
+               default:
+                       color = "";
+       }
+       
+       switch(place % 10) {
+               case 1:
+                       tail = "st";
+                       break;
+               case 2:
+                       tail = "nd";
+                       break;
+               case 3:
+                       tail = "rd";
+                       break;
+               default:
+                       tail = "th";
+       }
+       
+       str = strcat(color, ftos(place), tail);
+       if(tied)
+               return strcat("Tied for ", str);
+       else
+               return str;
+}
+
 string notif_arg_frag_ping(bool newline, float fping)
 {
        string s = newline ? "\n" : " ";
@@ -865,6 +948,18 @@ Notification Get_Notif_Ent(MSG net_type, int net_name)
                        optiona,                                 /* optiona     */ \
                        optionb);                                /* optionb     */ \
        }
+       
+#define MSG_MEDAL_NOTIF(name, defaultvalue, icon, anncename) \
+       NOTIF_ADD_AUTOCVAR(MEDAL_##name, defaultvalue) \
+       MSG_MEDAL_NOTIF_(0, MEDAL_##name, MEDAL_##name, defaultvalue, icon, anncename)
+
+#define MSG_MEDAL_NOTIF_(teamnum, name, cvarname, defaultvalue, icon, anncename) \
+       REGISTER(Notifications, name, m_id, new_pure(msg_medal_notification)) { \
+               Create_Notification_Entity      (this, defaultvalue, ACVNN(cvarname), MSG_MEDAL, strtoupper(#name), teamnum); \
+               Create_Notification_Entity_Medal(this, ACVNN(cvarname), strtoupper(#name), \
+                       icon, \
+                       anncename); \
+       }
 
 REGISTRY_BEGIN(Notifications)
 {
index 6115223b486b3e61382fc9fb2f1a709e4d7448d4..868b0b3b3defac79f1e46b5526b3279c93680d80 100644 (file)
@@ -7,6 +7,7 @@ REPLICATE_INIT(bool, cvar_cl_clippedspectating);
 REPLICATE_INIT(bool, cvar_cl_cts_noautoswitch);
 REPLICATE_INIT(float, cvar_cl_handicap);
 REPLICATE_INIT(bool, cvar_cl_noantilag);
+REPLICATE_INIT(bool, cvar_cl_chat_sounds);
 REPLICATE_INIT(string, cvar_g_xonoticversion);
 REPLICATE(cvar_cl_autoswitch, bool, "cl_autoswitch");
 REPLICATE(cvar_cl_autoscreenshot, int, "cl_autoscreenshot");
@@ -14,5 +15,6 @@ REPLICATE(cvar_cl_clippedspectating, bool, "cl_clippedspectating");
 REPLICATE(cvar_cl_cts_noautoswitch, bool, "cl_cts_noautoswitch");
 REPLICATE(cvar_cl_handicap, float, "cl_handicap");
 REPLICATE(cvar_cl_noantilag, bool, "cl_noantilag");
+REPLICATE(cvar_cl_chat_sounds, bool, "cl_chat_sounds");
 REPLICATE(cvar_g_xonoticversion, string, "g_xonoticversion");
 #endif
index 8f22b5c7525bcea5c80f01d594c9fc38a11660a7..9920170e7570fc23b2dc6a6d37f64bfd3f65adf1 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#define MAX_SCORE 64
+#define MAX_SCORE 128
 
 #define REGISTER_SP(id) REGISTER(Scores, SP, id, m_id, new_pure(PlayerScoreField))
 REGISTRY(Scores, MAX_SCORE)
@@ -85,12 +85,38 @@ REGISTER_SP(END);
 
 REGISTER_SP(PING);
 REGISTER_SP(PL);
+REGISTER_SP(COUNTRY); //LegendGuard adds new column for country label 05-04-2021
 REGISTER_SP(NAME);
 REGISTER_SP(SEPARATOR);
 
 REGISTER_SP(KDRATIO); // kills / deaths
 REGISTER_SP(SUM); // kills - deaths
 REGISTER_SP(FRAGS); // kills - suicides
+
+REGISTER_SP(MEDAL_AIRSHOT);
+REGISTER_SP(MEDAL_DAMAGE);
+REGISTER_SP(MEDAL_ELECTROBITCH);
+REGISTER_SP(MEDAL_EXCELLENT);
+REGISTER_SP(MEDAL_FIRSTBLOOD);
+REGISTER_SP(MEDAL_HEADSHOT);
+REGISTER_SP(MEDAL_HUMILIATION);
+REGISTER_SP(MEDAL_IMPRESSIVE);
+REGISTER_SP(MEDAL_YODA);
+REGISTER_SP(MEDAL_TELEFRAG);
+
+REGISTER_SP(MEDAL_ACCURACY);
+REGISTER_SP(MEDAL_ASSIST);
+REGISTER_SP(MEDAL_CAPTURE);
+REGISTER_SP(MEDAL_DEFENSE);
+REGISTER_SP(MEDAL_PERFECT);
+
+REGISTER_SP(MEDAL_KILLSTREAK_03);
+REGISTER_SP(MEDAL_KILLSTREAK_05);
+REGISTER_SP(MEDAL_KILLSTREAK_10);
+REGISTER_SP(MEDAL_KILLSTREAK_15);
+
+REGISTER_SP(SV_SURVIVALS);
+REGISTER_SP(SV_HUNTS);
 #endif
 
 
index d8d60c4a129a987cd297caaa549dab804318d1ec..7b94cacd2be9c9684100330b1a4c4e0dbe4fd38c 100644 (file)
@@ -96,6 +96,7 @@ SOUND(SEEKEREXP3, W_Sound("seekerexp3"));
 SOUND(SEEKER_FIRE, W_Sound("seeker_fire"));
 SOUND(SHOTGUN_FIRE, W_Sound("shotgun_fire"));
 SOUND(SHOTGUN_MELEE, W_Sound("shotgun_melee"));
+SOUND(SHOTGUN_MELEE_IMPACT, W_Sound("shotgun_melee_impact"));
 SOUND(STRENGTH_FIRE, W_Sound("strength_fire"));
 SOUND(TAGEXP1, W_Sound("tagexp1"));
 SOUND(TAGEXP2, W_Sound("tagexp2"));
@@ -110,8 +111,8 @@ SOUND(WEAPONPICKUP_NEW_TOYS, W_Sound("weaponpickup_new_toys"));
 SOUND(WEAPON_SWITCH, W_Sound("weapon_switch"));
 
 SOUND(CTF_CAPTURE_NEUTRAL, "ctf/capture");
-SOUND(CTF_CAPTURE_RED, "ctf/red_capture");
-SOUND(CTF_CAPTURE_BLUE, "ctf/blue_capture");
+SOUND(CTF_CAPTURE_RED, "ctf/red_capture_clean");
+SOUND(CTF_CAPTURE_BLUE, "ctf/blue_capture_clean");
 SOUND(CTF_CAPTURE_YELLOW, "ctf/yellow_capture");
 SOUND(CTF_CAPTURE_PINK, "ctf/pink_capture");
 Sound SND_CTF_CAPTURE(int teamid) {
@@ -125,8 +126,8 @@ Sound SND_CTF_CAPTURE(int teamid) {
 }
 
 SOUND(CTF_DROPPED_NEUTRAL,  "ctf/neutral_dropped");
-SOUND(CTF_DROPPED_RED,      "ctf/red_dropped");
-SOUND(CTF_DROPPED_BLUE,     "ctf/blue_dropped");
+SOUND(CTF_DROPPED_RED,      "ctf/red_dropped_clean");
+SOUND(CTF_DROPPED_BLUE,     "ctf/blue_dropped_clean");
 SOUND(CTF_DROPPED_YELLOW,   "ctf/yellow_dropped");
 SOUND(CTF_DROPPED_PINK,     "ctf/pink_dropped");
 Sound SND_CTF_DROPPED(int teamid) {
@@ -143,8 +144,8 @@ SOUND(CTF_PASS, "ctf/pass");
 SOUND(CTF_RESPAWN, "ctf/flag_respawn");
 
 SOUND(CTF_RETURNED_NEUTRAL,  "ctf/return");
-SOUND(CTF_RETURNED_RED,      "ctf/red_returned");
-SOUND(CTF_RETURNED_BLUE,     "ctf/blue_returned");
+SOUND(CTF_RETURNED_RED,      "ctf/red_returned_clean");
+SOUND(CTF_RETURNED_BLUE,     "ctf/blue_returned_clean");
 SOUND(CTF_RETURNED_YELLOW,   "ctf/yellow_returned");
 SOUND(CTF_RETURNED_PINK,     "ctf/pink_returned");
 Sound SND_CTF_RETURNED(int teamid) {
@@ -158,8 +159,8 @@ Sound SND_CTF_RETURNED(int teamid) {
 }
 
 SOUND(CTF_TAKEN_NEUTRAL,  "ctf/neutral_taken");
-SOUND(CTF_TAKEN_RED,      "ctf/red_taken");
-SOUND(CTF_TAKEN_BLUE,     "ctf/blue_taken");
+SOUND(CTF_TAKEN_RED,      "ctf/red_taken_clean");
+SOUND(CTF_TAKEN_BLUE,     "ctf/blue_taken_clean");
 SOUND(CTF_TAKEN_YELLOW,   "ctf/yellow_taken");
 SOUND(CTF_TAKEN_PINK,     "ctf/pink_taken");
 Sound SND_CTF_TAKEN(int teamid) {
@@ -273,6 +274,13 @@ Sound SND_GIB_SPLAT_RANDOM() {
 SOUND(HIT, "misc/hit");
 SOUND(TYPEHIT, "misc/typehit");
 SOUND(KILL, "misc/kill");
+SOUND(DEATH, "misc/death");
+SOUND(ENDCOUNT, "misc/endcount");
+SOUND(ENDMATCH, "misc/endmatch");
+SOUND(OVERTIME, "misc/overtime");
+SOUND(TIMEOUT, "misc/timeout");
+
+SOUND(MIDAIR, "misc/midair");
 
 SOUND(SPAWN, "misc/spawn");
 
index d174eeb6bac526e0bfd0a0fba21b779384456e97..9738c83785d7695f4c9067f6d1195da4c36c89e9 100644 (file)
@@ -24,7 +24,7 @@ void PlayerState_detach(entity this)
     PlayerState ps = PS(this);
        if (!ps) return;  // initial connect
        PS(this) = NULL;
-    Inventory_clear(this.inventory_store); // no need to network updates, as there is no inventory attached
+    //Inventory_clear(this.inventory_store); // no need to network updates, as there is no inventory attached
 
        if (ps.m_client != this) return;  // don't own state, spectator
        ps.ps_push(ps, this);
index 9b4394e45a62f1d0a2851555945521740c7c8e71..f93219c1f59f4452dee4c7956d6e752278ebe3a3 100644 (file)
@@ -78,6 +78,13 @@ float W_WeaponRateFactor(entity this);
 float game_stopped;
 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 round_delaytime;
+float overtime_starttime; // z411 point in time where first overtime started
+
+float timeout_last;
+float timeout_total_time;
+bool game_timeout;
+
 int autocvar_leadlimit;
 int overtimes; // overtimes added (-1 = sudden death)
 int timeout_status; // (values: 0, 1, 2) contains whether a timeout is not active (0), was called but still at leadtime (1) or is active (2)
@@ -90,6 +97,9 @@ int timeout_status; // (values: 0, 1, 2) contains whether a timeout is not activ
 #endif
 REGISTER_STAT(WEAPONRATEFACTOR, float, W_WeaponRateFactor(this))
 REGISTER_STAT(GAME_STOPPED, int, game_stopped)
+
+REGISTER_STAT(TIMEOUT_LAST, float, timeout_last)
+
 REGISTER_STAT(GAMESTARTTIME, float, game_starttime)
 /** arc heat in [0,1] */
 REGISTER_STAT(PRESSED_KEYS, int)
@@ -114,14 +124,11 @@ REGISTER_STAT(VEHICLESTAT_AMMO2, int)
 REGISTER_STAT(VEHICLESTAT_RELOAD2, int)
 REGISTER_STAT(VEHICLESTAT_W2MODE, int)
 REGISTER_STAT(NADE_TIMER, float)
-REGISTER_STAT(SECRETS_TOTAL, int, secrets_total)
-REGISTER_STAT(SECRETS_FOUND, int, secrets_found)
 REGISTER_STAT(RESPAWN_TIME, float)
 REGISTER_STAT(ROUNDSTARTTIME, float, round_starttime)
+REGISTER_STAT(ROUNDENDTIME, float, round_delaytime)
 REGISTER_STAT(OVERTIMES, int, overtimes)
 REGISTER_STAT(TIMEOUT_STATUS, int, timeout_status)
-REGISTER_STAT(MONSTERS_TOTAL, int)
-REGISTER_STAT(MONSTERS_KILLED, int)
 REGISTER_STAT(NADE_BONUS, float)
 REGISTER_STAT(NADE_BONUS_TYPE, int)
 REGISTER_STAT(NADE_BONUS_SCORE, float)
@@ -443,3 +450,5 @@ REGISTER_STAT(GUNALIGN, int)
 #ifdef SVQC
 SPECTATE_COPYFIELD(_STAT(GUNALIGN))
 #endif
+
+REGISTER_STAT(SURVIVAL_ROUNDTIMER, float)
index 62c3e7b162b2aa11e27962da6e49b218889cbc91..e99b001b255d676b55e5b6409e61da9def8ef435 100644 (file)
@@ -58,6 +58,12 @@ const string STATIC_NAME_TEAM_4 = "Pink";
 #ifdef CSQC
 bool teamplay;
 int myteam;
+
+// z411 used for custom names
+string teamname_red;
+string teamname_blue;
+string teamname_yellow;
+string teamname_pink;
 #endif
 
 string Team_ColorCode(int teamid)
@@ -86,6 +92,21 @@ vector Team_ColorRGB(int teamid)
        return '0 0 0';
 }
 
+#ifdef CSQC
+string Team_CustomName(int teamid)
+{
+       switch(teamid)
+       {
+               case NUM_TEAM_1: return ((teamname_red != "") ? teamname_red : "^1RED^7 team");
+               case NUM_TEAM_2: return ((teamname_blue != "")? teamname_blue : "^4BLUE^7 team");
+               case NUM_TEAM_3: return ((teamname_yellow != "") ? teamname_yellow : "^3YELLOW^7 team");
+               case NUM_TEAM_4: return ((teamname_pink != "") ? teamname_pink : "^6PINK^7 team");
+       }
+
+    return NAME_NEUTRAL;
+}
+#endif
+
 string Team_ColorName(int teamid)
 {
        switch(teamid)
index ca120d29535b154ecaeb4e9855cd8a5fc297183e..6c8fc763b377c2fc00f2f18c8c4dda7fae5042d2 100644 (file)
@@ -2033,7 +2033,7 @@ int LostMovetypeFollow(entity ent)
 string playername(string thename, int teamid, bool team_colorize)
 {
        TC(int, teamid);
-       bool do_colorize = (teamplay && team_colorize);
+       bool do_colorize = (teamplay && team_colorize && Team_IsValidTeam(teamid));
 #ifdef SVQC
        if(do_colorize && !intermission_running)
 #else
index ef08d30b8e93a2ae424418e56bc477f88efa36dc..f71c76b69cc614e2029aa2c5484553c74814da01 100644 (file)
@@ -22,8 +22,9 @@ void W_Devastator_Explode(entity this, entity directhitentity)
                if(IS_PLAYER(directhitentity))
                        if(DIFF_TEAM(this.realowner, directhitentity))
                                if(!IS_DEAD(directhitentity))
-                                       if(IsFlying(directhitentity))
-                                               Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
+                                       if(IsFlying(directhitentity)) {
+                                               Give_Medal(this.realowner, AIRSHOT);
+                                       }
 
        this.event_damage = func_null;
        this.takedamage = DAMAGE_NO;
@@ -206,6 +207,7 @@ void W_Devastator_Think(entity this)
        vector desireddir, olddir, newdir, desiredorigin, goal;
        float velspeed, f;
        this.nextthink = time;
+       if(game_timeout) { set_movetype(this, MOVETYPE_NONE); this.disableclientprediction = 2; return; } else { set_movetype(this, MOVETYPE_FLY); this.disableclientprediction = 0; }
        if(time > this.cnt)
        {
                this.projectiledeathtype |= HITTYPE_BOUNCE;
index 280267a9ad3de6368294cb332cc34a829c261720..a5c2b86e8bd067d434ade4edf6a57f3324dd2c6d 100644 (file)
@@ -77,13 +77,15 @@ void W_Electro_ExplodeCombo(entity this)
 
 void W_Electro_Explode(entity this, entity directhitentity)
 {
-       if(directhitentity.takedamage == DAMAGE_AIM)
+       /*if(directhitentity.takedamage == DAMAGE_AIM)
                if(IS_PLAYER(directhitentity))
                        if(DIFF_TEAM(this.realowner, directhitentity))
                                if(!IS_DEAD(directhitentity))
-                                       if(IsFlying(directhitentity))
-                                               Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_ELECTROBITCH);
-
+                                       if(IsFlying(directhitentity)) {
+                                               Give_Medal(this.realowner, ELECTROBITCH);
+                                       }
+       */
+       
        this.event_damage = func_null;
        this.takedamage = DAMAGE_NO;
        this.velocity = this.movedir; // .velocity must be != '0 0 0' for particle fx and decal to work
index 442f88265e52a0f5462079e63a96bde3fc8d27e1..80c8a56f31b4368708dd53847a1ea730b2f6b924 100644 (file)
@@ -8,8 +8,9 @@ void W_Mortar_Grenade_Explode(entity this, entity directhitentity)
                if(IS_PLAYER(directhitentity))
                        if(DIFF_TEAM(this.realowner, directhitentity))
                                if(!IS_DEAD(directhitentity))
-                                       if(IsFlying(directhitentity))
-                                               Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
+                                       if(IsFlying(directhitentity)) {
+                                               Give_Medal(this.realowner, AIRSHOT);
+                                       }
 
        this.event_damage = func_null;
        this.takedamage = DAMAGE_NO;
@@ -33,8 +34,9 @@ void W_Mortar_Grenade_Explode2(entity this, entity directhitentity)
                if(IS_PLAYER(directhitentity))
                        if(DIFF_TEAM(this.realowner, directhitentity))
                                if(!IS_DEAD(directhitentity))
-                                       if(IsFlying(directhitentity))
-                                               Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
+                                       if(IsFlying(directhitentity)) {
+                                               Give_Medal(this.realowner, AIRSHOT);
+                                       }
 
        this.event_damage = func_null;
        this.takedamage = DAMAGE_NO;
index 65cc0d9d926323840f682a60c5fc046ba1ec7dd7..9de4375100671dc6a60e25982a3b2cdfbd013f59 100644 (file)
@@ -96,6 +96,7 @@ void W_Shotgun_Melee_Think(entity this)
 
                        //print(strcat(this.realowner.netname, " hitting ", target_victim.netname, " with ", strcat(ftos(swing_damage), " damage (factor: ", ftos(swing_factor), ") at "), ftos(time), " seconds.\n"));
 
+                       sound(target_victim, CH_SHOTS, SND_SHOTGUN_MELEE_IMPACT, VOL_BASE, ATTEN_NORM);
                        Damage(target_victim, this.realowner, this.realowner,
                                swing_damage, WEP_SHOTGUN.m_id | HITTYPE_SECONDARY, this.weaponentity_fld,
                                this.realowner.origin + this.realowner.view_ofs,
index 4066efc4e00d0d346bc662f2088829ec7228972c..9348f12170588b5d5aeb4301a68a859a8d28d0eb 100644 (file)
@@ -125,7 +125,7 @@ void W_Vaporizer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        sound (actor, CH_WEAPON_A, SND_MINSTANEXFIRE, VOL_BASE * 0.8, ATTEN_NORM);
 
        yoda = 0;
-       impressive_hits = 0;
+       //impressive_hits = 0;
        FireRailgunBullet(actor, weaponentity, w_shotorg, w_shotorg + w_shotdir * max_shot_distance, vaporizer_damage, true, WEP_CVAR_PRI(vaporizer, force), 0, 0, 0, 0, thiswep.m_id);
 
        // do this now, as goodhits is disabled below
@@ -133,13 +133,16 @@ void W_Vaporizer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        W_MuzzleFlash(thiswep, actor, weaponentity, w_shotorg, normalize(v - w_shotorg));
        SendCSQCVaporizerBeamParticle(actor, impressive_hits);
 
-       if(yoda && flying)
-               Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
-       if(impressive_hits && actor.vaporizer_lasthit)
+       if(yoda && flying) {
+               Give_Medal(actor, YODA);
+       }
+       
+       // We're gonna disable Impressive medals for the vaporizer.
+       /*if(impressive_hits && actor.vaporizer_lasthit)
        {
-               Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_IMPRESSIVE);
+               Give_Medal(actor, IMPRESSIVE);
                impressive_hits = 0; // only every second time
-       }
+       }*/
 
        actor.vaporizer_lasthit = impressive_hits;
 
@@ -164,8 +167,9 @@ void W_RocketMinsta_Laser_Explode(entity this, entity directhitentity)
                if(IS_PLAYER(directhitentity))
                        if(DIFF_TEAM(this.realowner, directhitentity))
                                if(!IS_DEAD(directhitentity))
-                                       if(IsFlying(directhitentity))
-                                               Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_ELECTROBITCH);
+                                       if(IsFlying(directhitentity)) {
+                                               Give_Medal(this.realowner, ELECTROBITCH);
+                                       }
 
        this.event_damage = func_null;
        this.takedamage = DAMAGE_NO;
@@ -316,7 +320,7 @@ METHOD(Vaporizer, wr_think, void(entity thiswep, entity actor, .entity weaponent
 }
 METHOD(Vaporizer, wr_setup, void(entity thiswep, entity actor, .entity weaponentity))
 {
-    actor.vaporizer_lasthit = 0;
+    //actor.vaporizer_lasthit = 0;
 }
 METHOD(Vaporizer, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
 {
index d9cacac00de1e5092b13d52f747fc741dadfd2dc..b2b629fdc7df77ebebf4b8017a762ddaf29a018d 100644 (file)
@@ -131,11 +131,16 @@ void W_Vortex_Attack(Weapon thiswep, entity actor, .entity weaponentity, float i
        impressive_hits = 0;
        FireRailgunBullet(actor, weaponentity, w_shotorg, w_shotorg + w_shotdir * max_shot_distance, mydmg, false, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, dtype);
 
-       if(yoda && flying)
-               Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
+       if(yoda && flying) {
+               if(charge == 1) // play additional sound if we hit in the air with maximum damage
+                       sound(actor, CH_INFO, SND_MIDAIR, VOL_BASE, ATTN_NONE);
+               
+               Give_Medal(actor, YODA);
+       }
+       
        if(impressive_hits && actor.vortex_lasthit)
        {
-               Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_IMPRESSIVE);
+               Give_Medal(actor, IMPRESSIVE);
                impressive_hits = 0; // only every second time
        }
 
index 2d80a7a61ae89b1266299984f8a783605d9426ab..b19708ae1d2028ff389cf544480262a381625839 100644 (file)
@@ -18,7 +18,7 @@ CLASS(Vortex, Weapon)
 /* reticle   */ ATTRIB(Vortex, w_reticle, string, "gfx/reticle_nex");
 /* wepimg    */ ATTRIB(Vortex, model2, string, "weaponnex");
 /* refname   */ ATTRIB(Vortex, netname, string, "vortex");
-/* wepname   */ ATTRIB(Vortex, m_name, string, _("Vortex"));
+/* wepname   */ ATTRIB(Vortex, m_name, string, _("Nex"));
 /* legacy    */ ATTRIB(Vortex, m_deprecated_netname, string, "nex");
 
 #define X(BEGIN, P, END, class, prefix) \
index 1454d0049fe76b0d6211f0e98e7379b47bb20857..4921bdfcfa4800facd734eeca7af5624cf19b347 100644 (file)
@@ -44,7 +44,9 @@ void sys_phys_ai(entity this)
 void sys_phys_pregame_hold(entity this)
 {
        if (!IS_PLAYER(this)) { return; }
-       const bool allowed_to_move = (time >= game_starttime && !game_stopped);
+       // z411
+       //const bool allowed_to_move = (time >= game_starttime && !game_stopped);
+       const bool allowed_to_move = (!game_stopped && !game_timeout);
        if (!allowed_to_move) {
                this.velocity = '0 0 0';
                set_movetype(this, MOVETYPE_NONE);
index 5a72b59774478a32cf5aacaf046ad4a864ab510b..62307cc15b7fea51f973ac46212bfcc299a3efc4 100644 (file)
@@ -3,6 +3,7 @@
 #include <common/gamemodes/_mod.qh>
 #include <common/mapobjects/target/location.qh>
 #include <common/mapobjects/triggers.qh>
+#include <common/net_linked.qh>
 #include <common/notifications/all.qh>
 #include <common/teams.qh>
 #include <common/util.qh>
@@ -87,8 +88,14 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
        */
 
        string namestr = "";
-       if (source)
-               namestr = playername(source.netname, source.team, (autocvar_g_chat_teamcolors && IS_PLAYER(source)));
+       if (source) {
+               namestr = playername(source.netname, source.team, (autocvar_g_chat_teamcolors));
+               
+               if (IS_DEAD(source) || source.frags == FRAGS_PLAYER_OUT_OF_GAME)
+                       namestr = strcat("(DEAD) ", namestr);
+               else if (IS_OBSERVER(source) || IS_SPEC(source))
+                       namestr = strcat("(s) ", namestr);
+       }
 
        string colorprefix = (strdecolorize(namestr) == namestr) ? "^3" : "^7";
 
@@ -130,11 +137,11 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
                                //msgin = strreplace("/me", "", msgin);
                                //msgin = substring(msgin, 3, strlen(msgin));
                                //msgin = strreplace("/me", strcat(colorstr, "(", colorprefix, namestr, colorstr, ")^7"), msgin);
-                               msgstr = strcat("\{1}\{13}^4* ", "^7", msgin);
+                               msgstr = strcat("\{1}\{13}^4* ", "^5", msgin);
                        }
                        else
-                               msgstr = strcat("\{1}\{13}", colorstr, "(", colorprefix, namestr, colorstr, ") ^7", msgin);
-                       cmsgstr = strcat(colorstr, "(", colorprefix, namestr, colorstr, ")\n^7", msgin);
+                               msgstr = strcat("\{1}\{13}", colorstr, "(Team) ", namestr, colorstr, ": ^5", msgin);
+                       cmsgstr = strcat(colorstr, "(", colorprefix, namestr, colorstr, ")\n^5", msgin);
                }
                else
                {
@@ -225,8 +232,9 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
                                flood = 1;
                }
 
-               if (timeout_status == TIMEOUT_ACTIVE) // when game is paused, no flood protection
-                       source.(flood_field) = flood = 0;
+               // z411 : Why?
+               //if (timeout_status == TIMEOUT_ACTIVE) // when game is paused, no flood protection
+               //      source.(flood_field) = flood = 0;
        }
 
        string sourcemsgstr, sourcecmsgstr;
@@ -356,7 +364,9 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
 
                                sprint(it, msgstr);
                        });
-                       event_log_msg = sprintf(":chat_spec:%d:%s", source.playerid, strreplace("\n", " ", msgin));
+                       
+                       if(!play_chatsound(source, msgin))
+                               event_log_msg = sprintf(":chat_spec:%d:%s", source.playerid, strreplace("\n", " ", msgin));
                }
                else
                {
@@ -371,7 +381,9 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
 
                                sprint(it, msgstr);
                        });
-                       event_log_msg = sprintf(":chat:%d:%s", source.playerid, strreplace("\n", " ", msgin));
+                       
+                       if(!play_chatsound(source, msgin))
+                               event_log_msg = sprintf(":chat:%d:%s", source.playerid, strreplace("\n", " ", msgin));
                }
        }
 
@@ -382,6 +394,32 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
        return ret;
 }
 
+bool play_chatsound(entity source, string msgin)
+{
+       if(autocvar_sv_chat_sounds && CS_CVAR(source).cvar_cl_chat_sounds) {
+               var .float flood_sound = floodcontrol_chatsound;
+               
+               if (source.(flood_sound) < time - autocvar_sv_chat_sounds_flood) {
+                       string rawmsg;
+                       bool found = false;
+                       rawmsg = strreplace("\n", " ", msgin);
+                       
+                       FOREACH_WORD(autocvar_sv_chat_sounds_list, it == rawmsg, { found = true; });
+                       if (found) {
+                               FOREACH_CLIENT(IS_REAL_CLIENT(it) && CS_CVAR(it).cvar_cl_chat_sounds, {
+                                       msg_entity = it;
+                                       WriteHeader(MSG_ONE, TE_CSQC_CHATSOUND);
+                                       WriteString(MSG_ONE, rawmsg);
+                               });
+                               source.(flood_sound) = time;
+                               return true;
+                       }
+               }
+       }
+       
+       return false;
+}
+
 entity findnearest(vector point, bool checkitems, vector axismod)
 {
     vector dist;
index a921f61ece5c0cd41e60a4344dfffdf7bf4637cb..c07a23124974da2bb6367ffb55d461f63286d953 100644 (file)
@@ -18,6 +18,10 @@ int autocvar_g_chat_nospectators;
 bool autocvar_g_chat_teamcolors;
 bool autocvar_g_chat_tellprivacy;
 
+bool autocvar_sv_chat_sounds;
+float autocvar_sv_chat_sounds_flood;
+string autocvar_sv_chat_sounds_list;
+
 const float NUM_NEAREST_ENTITIES = 4;
 entity nearest_entity[NUM_NEAREST_ENTITIES];
 float nearest_length[NUM_NEAREST_ENTITIES];
@@ -27,10 +31,12 @@ float nearest_length[NUM_NEAREST_ENTITIES];
 .float floodcontrol_chattell;
 .float floodcontrol_voice;
 .float floodcontrol_voiceteam;
+.float floodcontrol_chatsound;
 
 #define CHAT_NOSPECTATORS() ((autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !warmup_stage))
 
 int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodcontrol);
+bool play_chatsound(entity source, string msgin);
 
 string NearestLocation(vector p);
 
index c1ee3aceb39780f2b3ede953fd45ff0aac798c60..18051aa08a607d4bea777cd59b08ec568c36d7b7 100644 (file)
@@ -101,6 +101,16 @@ void send_CSQC_teamnagger() {
        WriteHeader(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
 }
 
+void send_TeamNames(int channel, entity to) {
+       msg_entity = to;
+       
+       WriteHeader(channel, TE_CSQC_TEAMNAMES);
+       WriteString(channel, autocvar_g_teamnames_red);
+       WriteString(channel, autocvar_g_teamnames_blue);
+       WriteString(channel, autocvar_g_teamnames_yellow);
+       WriteString(channel, autocvar_g_teamnames_pink);
+}
+
 int CountSpectators(entity player, entity to)
 {
        if(!player) { return 0; } // not sure how, but best to be safe
@@ -414,6 +424,12 @@ void PutObserverInServer(entity this, bool is_forced, bool use_spawnpoint)
 
        if (CS(this).just_joined)
                CS(this).just_joined = false;
+       if (this.wants_join)
+               this.wants_join = 0;
+
+       // for RJZ
+       if (autocvar_rjz_count_shards)
+               send_TotalShards(this);
 }
 
 int player_getspecies(entity this)
@@ -538,17 +554,34 @@ void FixPlayermodel(entity player)
                                setcolor(player, stof(autocvar_sv_defaultplayercolors));
 }
 
-void GiveWarmupResources(entity this)
+void ResetPlayerResources(entity this)
 {
-       SetResource(this, RES_SHELLS, warmup_start_ammo_shells);
-       SetResource(this, RES_BULLETS, warmup_start_ammo_nails);
-       SetResource(this, RES_ROCKETS, warmup_start_ammo_rockets);
-       SetResource(this, RES_CELLS, warmup_start_ammo_cells);
-       SetResource(this, RES_PLASMA, warmup_start_ammo_plasma);
-       SetResource(this, RES_FUEL, warmup_start_ammo_fuel);
-       SetResource(this, RES_HEALTH, warmup_start_health);
-       SetResource(this, RES_ARMOR, warmup_start_armorvalue);
-       STAT(WEAPONS, this) = WARMUP_START_WEAPONS;
+       if (warmup_stage) {
+               SetResource(this, RES_SHELLS, warmup_start_ammo_shells);
+               SetResource(this, RES_BULLETS, warmup_start_ammo_nails);
+               SetResource(this, RES_ROCKETS, warmup_start_ammo_rockets);
+               SetResource(this, RES_CELLS, warmup_start_ammo_cells);
+               SetResource(this, RES_PLASMA, warmup_start_ammo_plasma);
+               SetResource(this, RES_FUEL, warmup_start_ammo_fuel);
+               SetResource(this, RES_HEALTH, warmup_start_health);
+               SetResource(this, RES_ARMOR, warmup_start_armorvalue);
+               STAT(WEAPONS, this) = WARMUP_START_WEAPONS;
+       } else {
+               SetResource(this, RES_SHELLS, start_ammo_shells);
+               SetResource(this, RES_BULLETS, start_ammo_nails);
+               SetResource(this, RES_ROCKETS, start_ammo_rockets);
+               SetResource(this, RES_CELLS, start_ammo_cells);
+               SetResource(this, RES_PLASMA, start_ammo_plasma);
+               SetResource(this, RES_FUEL, start_ammo_fuel);
+               SetResource(this, RES_HEALTH, start_health);
+               SetResource(this, RES_ARMOR, start_armorvalue);
+               STAT(WEAPONS, this) = start_weapons;
+               if (MUTATOR_CALLHOOK(ForbidRandomStartWeapons, this) == false)
+               {
+                       GiveRandomWeapons(this, random_start_weapons_count,
+                               autocvar_g_random_start_weapons, random_start_ammo);
+               }
+       }
 }
 
 void PutPlayerInServer(entity this)
@@ -593,25 +626,8 @@ void PutPlayerInServer(entity this)
        this.takedamage = DAMAGE_AIM;
        this.effects = EF_TELEPORT_BIT | EF_RESTARTANIM_BIT;
 
-       if (warmup_stage)
-               GiveWarmupResources(this);
-       else
-       {
-               SetResource(this, RES_SHELLS, start_ammo_shells);
-               SetResource(this, RES_BULLETS, start_ammo_nails);
-               SetResource(this, RES_ROCKETS, start_ammo_rockets);
-               SetResource(this, RES_CELLS, start_ammo_cells);
-               SetResource(this, RES_PLASMA, start_ammo_plasma);
-               SetResource(this, RES_FUEL, start_ammo_fuel);
-               SetResource(this, RES_HEALTH, start_health);
-               SetResource(this, RES_ARMOR, start_armorvalue);
-               STAT(WEAPONS, this) = start_weapons;
-               if (MUTATOR_CALLHOOK(ForbidRandomStartWeapons, this) == false)
-               {
-                       GiveRandomWeapons(this, random_start_weapons_count,
-                               autocvar_g_random_start_weapons, random_start_ammo);
-               }
-       }
+       ResetPlayerResources(this);
+
        SetSpectatee_status(this, 0);
 
        PS(this).dual_weapons = '0 0 0';
@@ -850,7 +866,9 @@ void PutClientInServer(entity this)
        } else if (IS_PLAYER(this)) {
                PutPlayerInServer(this);
        }
-
+       // send team names
+       if(teamplay && IS_REAL_CLIENT(this))
+               send_TeamNames(MSG_ONE, this);
        bot_relinkplayerlist();
 }
 
@@ -890,6 +908,13 @@ void ClientInit_misc(entity this)
        WriteByte(channel, this.cnt * 255.0); // g_balance_damagepush_speedfactor
        WriteByte(channel, serverflags);
        WriteCoord(channel, autocvar_g_trueaim_minrange);
+       
+       // z411 send full hostname
+       WriteString(channel, (autocvar_hostname_full != "" ? autocvar_hostname_full : autocvar_hostname));
+       WriteString(channel, autocvar_sv_motd_permanent);
+       
+       // z411 send client countdown type
+       WriteByte(channel, autocvar_sv_timer_countdown);
 }
 
 void ClientInit_CheckUpdate(entity this)
@@ -1115,10 +1140,15 @@ void ClientConnect(entity this)
        else
                CS(this).allowed_timeouts = autocvar_sv_timeout_number;
 
-       if (autocvar_sv_eventlog)
+       if (autocvar_sv_eventlog) {
                GameLogEcho(strcat(":join:", ftos(this.playerid), ":", ftos(etof(this)), ":", ((IS_REAL_CLIENT(this)) ? GameLog_ProcessIP(this.netaddress) : "bot"), ":", playername(this.netname, this.team, false)));
+               
+               /* z411 for RJZ */
+               if(autocvar_rjz_ranks) GameLogEcho(strcat(":idfp:", ftos(etof(this)), ":", this.crypto_idfp));
+       }
 
        CS(this).just_joined = true;  // stop spamming the eventlog with additional lines when the client connects
+       this.wants_join = 0;
 
        stuffcmd(this, clientstuff, "\n");
        stuffcmd(this, "cl_particles_reloadeffects\n"); // TODO do we still need this?
@@ -1290,6 +1320,9 @@ void ClientDisconnect(entity this)
 
        if (player_count == 0)
                localcmd("\nsv_hook_lastleave\n");
+
+       if (teamplay && autocvar_g_balance_teams_remove)
+               TeamBalance_RemoveExcessPlayers(NULL);
 }
 
 void ChatBubbleThink(entity this)
@@ -1985,15 +2018,17 @@ void ShowRespawnCountdown(entity this)
        }
 }
 
-.bool team_selected;
 bool ShowTeamSelection(entity this)
 {
        if (!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || this.team_selected || (CS(this).wasplayer && autocvar_g_changeteam_banned) || Player_HasRealForcedTeam(this))
                return false;
+       if (SpectatorWantsJoin(this))
+               return false;
        if (frametime) // once per frame is more than enough
                stuffcmd(this, "_scoreboard_team_selection 1\n");
        return true;
 }
+
 void Join(entity this)
 {
        if (autocvar_g_campaign && !campaign_bots_may_start && !game_stopped && time >= game_starttime)
@@ -2001,8 +2036,12 @@ void Join(entity this)
 
        TRANSMUTE(Player, this);
 
+       entity queued_join = SpectatorWantsJoin(this);
+       if(queued_join)
+               this.team_selected = false; // Don't let this player select team
+
        if(!this.team_selected)
-       if(autocvar_g_campaign || autocvar_g_balance_teams)
+       if(autocvar_g_campaign || autocvar_g_balance_teams || queued_join)
                TeamBalance_JoinBestTeam(this);
 
        if(autocvar_g_campaign)
@@ -2015,10 +2054,22 @@ void Join(entity this)
        if(IS_PLAYER(this))
        if(teamplay && this.team != -1)
        {
+               if(this.wants_join)
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_JOIN_PLAY_TEAM), this.netname);
        }
        else
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_JOIN_PLAY, this.netname);
        this.team_selected = false;
+       
+       // z411
+       // send constant ready notification
+       if(warmup_stage)
+               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MISSING_READY);
+
+       this.wants_join = 0;
+
+       if(queued_join)
+               Join(queued_join);
 }
 
 int GetPlayerLimit()
@@ -2091,6 +2142,17 @@ int nJoinAllowed(entity this, entity ignore)
        return free_slots;
 }
 
+bool queuePlayer(entity this)
+{
+       if(IS_QUEUE_NEEDED(this) && !SpectatorWantsJoin(this))
+       {
+               if(autocvar_g_balance_teams)
+                       TeamBalance_JoinBestTeam(this);
+               return true;
+       }
+       return false;
+}
+
 bool joinAllowed(entity this)
 {
        if (CS(this).version_mismatch) return false;
@@ -2099,6 +2161,8 @@ bool joinAllowed(entity this)
        if (teamplay && lockteams) return false;
        if (MUTATOR_CALLHOOK(ForbidSpawn, this)) return false;
        if (ShowTeamSelection(this)) return false;
+       if (this.wants_join) return false;
+       if (queuePlayer(this)) return false;
        return true;
 }
 
@@ -2138,12 +2202,13 @@ bool PlayerThink(entity this)
                return false;
        }
 
-       if (timeout_status == TIMEOUT_ACTIVE) {
-               // don't allow the player to turn around while game is paused
+       if (game_timeout) {
+        // don't allow the player to turn around while game is paused
                // FIXME turn this into CSQC stuff
                this.v_angle = this.lastV_angle;
                this.angles = this.lastV_angle;
                this.fixangle = true;
+               return false;
        }
 
        if (frametime) player_powerups(this);
@@ -2793,6 +2858,8 @@ void PlayerFrame (entity this)
                                {
                                        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_MOVETOSPEC_IDLING, this.netname, maxidle_time);
                                        PutObserverInServer(this, true, true);
+                                       if(autocvar_g_balance_teams_remove)
+                                               TeamBalance_RemoveExcessPlayers(this);
                                }
                                else
                                {
index 9611df4e87980f2fb639198e7f94fd1cae7f70ca..cb71a3eaa59298632061a5276fbeb6475dc5910c 100644 (file)
@@ -50,6 +50,7 @@ float autocvar_gameversion_max;
 string autocvar_hostname;
 int autocvar_spawn_debug;
 string autocvar_sv_motd;
+string autocvar_sv_motd_permanent;
 int autocvar_sv_name_maxlength = 64;
 string autocvar_sv_quickmenu_file;
 bool autocvar_sv_servermodelsonly;
@@ -58,6 +59,21 @@ int autocvar_sv_spectate;
 bool autocvar_sv_teamnagger;
 float autocvar_sv_player_scale;
 
+// z411
+string autocvar_hostname_full;
+string autocvar_g_teamnames_red;
+string autocvar_g_teamnames_blue;
+string autocvar_g_teamnames_yellow;
+string autocvar_g_teamnames_pink;
+
+void send_TeamNames(int channel, entity to);
+
+// Medals
+float autocvar_g_medals_excellent_time = 2;
+
+// Timer
+int autocvar_sv_timer_countdown = 1; // 0 = disabled, 1 = enabled, 2 = spect only
+
 // WEAPONTODO
 .string weaponorder_byimpulse;
 
@@ -72,7 +88,9 @@ float autocvar_sv_player_scale;
 .int spectatee_status;
 .bool zoomstate;
 
+.bool team_selected;
 .bool just_joined;
+.bool wants_join;
 
 .int pressedkeys;
 
@@ -89,6 +107,8 @@ CLASS(Client, Object)
     ATTRIB(Client, colormap, int, this.colormap);
     ATTRIB(Client, team, int, this.team);
     ATTRIB(Client, clientcolors, int, this.clientcolors);
+       ATTRIB(Client, countrycode, int, this.countrycode);
+       ATTRIB(Client, rank, string, this.rank);
     /** Client IP */
     ATTRIB(Client, netaddress, string, this.netaddress);
     ATTRIB(Client, playermodel, string, this.playermodel);
@@ -158,6 +178,7 @@ CLASS(Client, Object)
     ATTRIB(Client, teamkill_soundsource, entity, this.teamkill_soundsource);
     ATTRIB(Client, usekeypressed, bool, this.usekeypressed);
     ATTRIB(Client, jointime, float, this.jointime);
+    ATTRIB(Client, wants_join, bool, this.wants_join);
     ATTRIB(Client, spectatortime, float, this.spectatortime);
     ATTRIB(Client, startplaytime, float, this.startplaytime);
     ATTRIB(Client, version_nagtime, float, this.version_nagtime);
@@ -204,6 +225,7 @@ CLASS(Client, Object)
     ATTRIB(Client, cvar_cl_pokenade_type, string, this.cvar_cl_pokenade_type);
     ATTRIB(Client, cvar_cl_spawn_near_teammate, bool, this.cvar_cl_spawn_near_teammate);
     ATTRIB(Client, cvar_cl_gunalign, int, this.cvar_cl_gunalign);
+       ATTRIB(Client, cvar_cl_chat_sounds, bool, this.cvar_cl_chat_sounds);
     ATTRIB(Client, cvar_cl_handicap, float, this.cvar_cl_handicap);
     ATTRIB(Client, cvar_cl_clippedspectating, bool, this.cvar_cl_clippedspectating);
     ATTRIB(Client, cvar_cl_autoscreenshot, int, this.cvar_cl_autoscreenshot);
@@ -308,7 +330,10 @@ bool independent_players;
 #define IS_INDEPENDENT_PLAYER(e) ((e).solid == SOLID_TRIGGER)
 #define MAKE_INDEPENDENT_PLAYER(e) (((e).solid = SOLID_TRIGGER), ((e).frags = FRAGS_PLAYER_OUT_OF_GAME))
 
+.float lastkill;
+.int countrycode;
 .int killcount;
+.string rank; // RJZ
 
 //flood fields
 .float nickspamtime; // time of last nick change
@@ -392,7 +417,7 @@ void SetSpectatee_status(entity this, int spectatee_num);
 
 void FixPlayermodel(entity player);
 
-void GiveWarmupResources(entity this);
+void ResetPlayerResources(entity this);
 
 void ClientInit_misc(entity this);
 
@@ -408,3 +433,9 @@ void PlayerFrame (entity this);
 #define SPECTATE_COPYFIELD(fld) SPECTATE_COPY() { this.(fld) = spectatee.(fld); }
 
 const int MAX_SPECTATORS = 7;
+
+float _medal_times;
+#define Give_Medal(entity,medalname) \
+       _medal_times = GameRules_scoring_add(entity, MEDAL_##medalname, 1); \
+       Send_Notification(NOTIF_ONE, entity, MSG_MEDAL, MEDAL_##medalname, _medal_times);
+
index 296a95bfe5f384c9d8428626f0a1cbd0282fff2f..32c8d9faabb776478af0a07dd17601bd739ca7de 100644 (file)
@@ -25,7 +25,15 @@ void ClientKill_Now_TeamChange(entity this)
        {
                if (blockSpectators)
                        Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
-               PutObserverInServer(this, false, true);
+
+               if (this.wants_join)
+                       SetPlayerTeam(this, -1, TEAM_CHANGE_SPECTATOR);
+               else
+               {
+                       PutObserverInServer(this, false, true);
+                       if(autocvar_g_balance_teams_remove)
+                               TeamBalance_RemoveExcessPlayers(this);
+               }
        }
        else
        {
index b4f0bb3082a4980bb4ed6e9c31f1b958a88b1246..1d33f6b8efe42a38cb1fdd7d40be3bca10a5d1e8 100644 (file)
@@ -73,6 +73,49 @@ void BanCommand_banlist(int request)
        }
 }
 
+void BanCommand_kickkick(int request, int argc, string command)
+{
+               switch (request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if (argc >= 2)
+                       {
+                               entity client = GetIndexedEntity(argc, 1);
+                               float accepted = VerifyKickableEntity(client);
+                               float reason_arg;
+                               string reason;
+
+                               if (accepted > 0)
+                               {
+                                       reason_arg = next_token;
+
+                                       GET_BAN_REASON(reason, "No reason provided");
+
+                                       Ban_KickClient(client, reason);
+
+                                       return;
+                               }
+                               else
+                               {
+                                       LOG_INFO("kick: ", GetClientErrorString(accepted, argv(1)), ".");
+                               }
+                       }
+               }
+
+               default:
+                       LOG_INFOF("Incorrect parameters for ^2%s^7", argv(0));
+               case CMD_REQUEST_USAGE:
+               {
+                       LOG_HELP("Usage:^3 sv_cmd kickkick <client> [<reason>]");
+                       LOG_HELP("  <client> is the entity number or name of the player to kick,");
+                       LOG_HELP("  and <reason> is the string to label the ban with as reason for kicking.");
+                       LOG_HELP("See also: ^2kick^7");
+                       return;
+               }
+       }
+}
+
 void BanCommand_kickban(int request, int argc, string command)
 {
        switch (request)
@@ -467,6 +510,7 @@ void BanCommand_(int request)
 #define BAN_COMMANDS(request, arguments, command) \
        BAN_COMMAND("ban",          BanCommand_ban(request, arguments, command),        "Ban an IP address or a range of addresses (like 1.2.3)") \
        BAN_COMMAND("banlist",      BanCommand_banlist(request),                        "List all existing bans") \
+       BAN_COMMAND("kickkick",     BanCommand_kickkick(request, arguments, command),   "Disconnect a client") \
        BAN_COMMAND("kickban",      BanCommand_kickban(request, arguments, command),    "Disconnect a client and ban it at the same time") \
        BAN_COMMAND("mute",         BanCommand_mute(request, arguments, command),       "Disallow a client from talking by muting them") \
        BAN_COMMAND("playban",      BanCommand_playban(request, arguments, command),    "Force to spectate a client permanently") \
index f93880a682d45d6b50c7983c18778b9968ebc1f4..52ff6a644db1f02f590d7df5e0fb4726f9f6273a 100644 (file)
@@ -356,7 +356,7 @@ void ClientCommand_join(entity caller, int request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if (!game_stopped && IS_CLIENT(caller) && !IS_PLAYER(caller))
+                       if (!game_stopped && !game_timeout && IS_CLIENT(caller) && !IS_PLAYER(caller))
                        {
                                if (joinAllowed(caller))
                                        Join(caller);
@@ -465,7 +465,7 @@ void ClientCommand_ready(entity caller, int request)
                                else
                                {
                                        caller.ready = true;
-                                       bprint(playername(caller.netname, caller.team, false), "^2 is ready\n");
+                                       bprint("\{1}", playername(caller.netname, caller.team, false), "^2 is ready\n");
                                }
                                ReadyCount();
                        }
@@ -667,7 +667,7 @@ void ClientCommand_spectate(entity caller, int request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if (!intermission_running && IS_CLIENT(caller))
+                       if (!intermission_running && IS_CLIENT(caller) && !game_timeout)
                        {
                                if(argv(1) != "")
                                {
@@ -694,7 +694,7 @@ void ClientCommand_spectate(entity caller, int request)
 
                                if (mutator_returnvalue == MUT_SPECCMD_RETURN) return;
 
-                               if ((IS_PLAYER(caller) || mutator_returnvalue == MUT_SPECCMD_FORCE))
+                               if ((IS_PLAYER(caller) || mutator_returnvalue == MUT_SPECCMD_FORCE || caller.wants_join))
                                if (autocvar_sv_spectate == 1)
                                        ClientKill_TeamChange(caller, -2); // observe
                        }
@@ -711,6 +711,25 @@ void ClientCommand_spectate(entity caller, int request)
        }
 }
 
+void ClientCommand_sounds(entity caller, int request)
+{
+       switch (request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       sprint(caller, strcat("Available sounds: \n\n", autocvar_sv_chat_sounds_list, "\n"));
+                       return; // never fall through to usage
+               }
+
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(caller, "\nUsage:^3 cmd sounds\n");
+                       return;
+               }
+       }
+}
+
 void ClientCommand_suggestmap(entity caller, int request, int argc)
 {
        switch (request)
@@ -940,6 +959,7 @@ void ClientCommand_(entity caller, int request)
        CLIENT_COMMAND("selfstuff", ClientCommand_selfstuff(ent, request, command), "Stuffcmd a command to your own client") \
        CLIENT_COMMAND("sentcvar", ClientCommand_sentcvar(ent, request, arguments), "New system for sending a client cvar to the server") \
        CLIENT_COMMAND("spectate", ClientCommand_spectate(ent, request), "Become an observer") \
+       CLIENT_COMMAND("sounds", ClientCommand_sounds(ent, request), "Get list of commsnds") \
        CLIENT_COMMAND("suggestmap", ClientCommand_suggestmap(ent, request, arguments), "Suggest a map to the mapvote at match end") \
        CLIENT_COMMAND("tell", ClientCommand_tell(ent, request, arguments, command), "Send a message directly to a player") \
        CLIENT_COMMAND("voice", ClientCommand_voice(ent, request, arguments, command), "Send voice message via sound") \
index 6138bd8b5b4734ed0222d0eedbbcade4b2904aeb..33fc4a3ab4bf72336e28e307e1bee168bc6cf87f 100644 (file)
@@ -13,6 +13,7 @@
 #include <server/client.qh>
 #include <server/command/common.qh>
 #include <server/mutators/_mod.qh>
+#include <server/round_handler.qh>
 #include <server/scores.qh>
 #include <server/world.qh>
 
@@ -206,16 +207,36 @@ void timeout_handler_think(entity this)
                                if (timeout_time == autocvar_sv_timeout_resumetime) // play a warning sound when only <sv_timeout_resumetime> seconds are left
                                        Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_PREPARE);
 
-                               this.nextthink = time + TIMEOUT_SLOWMO_VALUE;       // think again in one second
+                               //this.nextthink = time + TIMEOUT_SLOWMO_VALUE;       // think again in one second
+                               this.nextthink = time + 1;
                                timeout_time -= 1;                                  // decrease the time counter
                        }
+                       else if (timeout_time == -1)  // infinite timer
+                       {
+                               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_TIMEOUT_ONGOING);
+                               this.nextthink = time + TIMEOUT_SLOWMO_VALUE;
+                       }
                        else  // time to end the timeout
                        {
                                Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_TIMEIN);
                                timeout_status = TIMEOUT_INACTIVE;
+                               float total_time = time - timeout_last;
 
                                // reset the slowmo value back to normal
-                               cvar_set("slowmo", ftos(orig_slowmo));
+                               // z411 TODO
+                               //cvar_set("slowmo", ftos(orig_slowmo));
+                               
+                               // Disable timeout and fix times
+                               game_timeout = false;
+                               timeout_total_time += total_time;
+                               game_starttime += total_time;
+                               if(round_starttime)
+                                       round_starttime += total_time;
+                               if(round_handler && round_handler_GetEndTime() > 0)
+                                       round_handler.round_endtime += total_time;
+
+                               LOG_INFOF("Timeout lasted %d secs", total_time);
+                               timeout_last = 0;
 
                                // unlock the view for players so they can move around again
                                FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
@@ -242,7 +263,12 @@ void timeout_handler_think(entity this)
                                timeout_status = TIMEOUT_ACTIVE;
 
                                // set the slowmo value to the timeout default slowmo value
-                               cvar_set("slowmo", ftos(TIMEOUT_SLOWMO_VALUE));
+                               //cvar_set("slowmo", ftos(TIMEOUT_SLOWMO_VALUE));
+                               game_timeout = true;
+                               timeout_last = time;
+                               
+                               // play timeout sound
+                               sound(NULL, CH_INFO, SND_TIMEOUT, VOL_BASE, ATTN_NONE);
 
                                // reset all the flood variables
                                FOREACH_CLIENT(true, {
@@ -677,7 +703,7 @@ void CommonCommand_timein(int request, entity caller)
                                                {
                                                        timeout_time = autocvar_sv_timeout_resumetime;
                                                        timeout_handler.nextthink = time;  // timeout_handler has to take care of it immediately
-                                                       bprint(strcat("^1Attention: ^7", GetCallerName(caller), " resumed the game! Prepare for battle!\n"));
+                                                       bprint(strcat("\{1}^1Attention: ^7", GetCallerName(caller), " resumed the game! Prepare for battle!\n"));
                                                        return;
                                                }
 
@@ -741,7 +767,7 @@ void CommonCommand_timeout(int request, entity caller)  // DEAR GOD THIS COMMAND
                                {
                                        if (caller)   CS(caller).allowed_timeouts -= 1;
                                        // write a bprint who started the timeout (and how many they have left)
-                                       bprint(GetCallerName(caller), " ^7called a timeout", (caller ? strcat(" (", ftos(CS(caller).allowed_timeouts), " timeout(s) left)") : ""), "!\n");
+                                       bprint("\{1}", GetCallerName(caller), " ^7called a timeout", (caller ? strcat(" (", ftos(CS(caller).allowed_timeouts), " timeout(s) left)") : ""), "!\n");
 
                                        timeout_status = TIMEOUT_LEADTIME;
                                        timeout_caller = caller;
@@ -751,7 +777,7 @@ void CommonCommand_timeout(int request, entity caller)  // DEAR GOD THIS COMMAND
                                        timeout_handler = new(timeout_handler);
                                        setthink(timeout_handler, timeout_handler_think);
                                        timeout_handler.nextthink = time;  // always let the entity think asap
-
+                                       
                                        Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_TIMEOUT);
                                }
                        }
index 3fdb1f968c5b75b96363643c1286837850d67ab4..d32aaef2095f12057c59e08c20f6c7f3a4f20c2b 100644 (file)
@@ -162,6 +162,61 @@ void GameCommand_adminmsg(int request, int argc)
        }
 }
 
+void GameCommand_teamname(int request, int argc)
+{
+       switch (request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if (argv(1) == "")
+                       {
+                               return;
+                       }
+                       if (!teamplay)
+                       {
+                               LOG_INFO("selectteam can only be used in teamgames");
+                               return;
+                       }
+                       
+                       switch (argv(1))
+                       {
+                               case "red":
+                               case "blue":
+                               case "yellow":
+                               case "pink":
+                               {
+                                       int tm = Team_ColorToTeam(argv(1));
+                                       if(argv(2) != "") {
+                                               cvar_set(strcat("g_teamnames_", argv(1)), argv(2));
+                                               bprintf("\{1}%s%s^7 team is now known as %s^7\n", Team_ColorCode(tm), Team_ColorName(tm), argv(2));
+                                       } else {
+                                               cvar_set(strcat("g_teamnames_", argv(1)), "");
+                                               bprintf("\{1}%s%s^7 team now doesn't have a team name\n", Team_ColorCode(tm), Team_ColorName(tm), argv(2));
+                                       }
+                                       
+                                       break;
+                               }
+                               default:
+                               {
+                                       return;
+                               }
+                       }
+                       
+                       send_TeamNames(MSG_BROADCAST, NULL);
+                       return;
+               }
+
+               default:
+                       LOG_INFOF("Incorrect parameters for ^2%s^7", argv(0));
+               case CMD_REQUEST_USAGE:
+               {
+                       LOG_HELP("Usage:^3 sv_cmd sendteams");
+                       LOG_HELP("  No arguments required.");
+                       return;
+               }
+       }
+}
+
 void GameCommand_allready(int request)
 {
        switch (request)
@@ -951,6 +1006,46 @@ void GameCommand_gotomap(int request, int argc)
        }
 }
 
+void GameCommand_ircmsg(int request, int argc, string command)
+{
+       /* IRCSay from the SMB Modpack */
+       switch (request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       string msgstr = substring(command, strlen(argv(0))+1, strlen(command));
+                       
+                       if(msgstr == "")
+                               return;
+                       
+                       string prefix;
+                       if(substring(msgstr, 0, 3) == "^4*") // actions
+                                       prefix = "\{3}";
+                       else
+                                       prefix = "\{1}";
+
+                       msgstr = strcat(prefix, strreplace("\n", " ", msgstr), "\n"); // newlines only are good for centerprint
+
+                       FOREACH_CLIENTSLOT(true,
+                       {
+                                       if(!intermission_running)
+                                       if((autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !(warmup_stage || game_stopped)))
+                                       if(IS_PLAYER(it))
+                                               continue;
+                                       if(IS_REAL_CLIENT(it))
+                                               sprint(it, msgstr);
+                       });
+               }
+               
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       LOG_HELP("Usage:^3 sv_cmd ircmsg message");
+                       return;
+               }
+       }
+}
+
 void GameCommand_lockteams(int request)
 {
        switch (request)
@@ -965,7 +1060,7 @@ void GameCommand_lockteams(int request)
                        if (teamplay)
                        {
                                lockteams = 1;
-                               bprint("^1The teams are now locked.\n");
+                               bprint("\{1}^1The teams are now locked.\n");
                        }
                        else
                        {
@@ -1011,6 +1106,72 @@ void GameCommand_make_mapinfo(int request)
        }
 }
 
+void GameCommand_setflag(int request, int argc)
+{
+       switch (request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       entity client;
+                       float accepted;
+                       
+                       client = GetFilteredEntity(argv(1));
+                       accepted = VerifyClientEntity(client, false, false);
+
+                       if (accepted <= 0)
+                       {
+                               LOG_INFO("^1ERROR^7: Couldn't set country flag");
+                               LOG_HELP("Usage:^3 sv_cmd setflag #client_id countrycode[0-249]");
+                               return;
+                       }
+                       
+                       client.countrycode = stof(argv(2));
+                       LOG_INFO("^2SUCCESS^7: Country flag set!");
+                       return;
+               }
+               default:
+                       LOG_INFOF("Incorrect parameters for ^2%s^7", argv(0));
+               case CMD_REQUEST_USAGE:
+               {
+                       LOG_HELP("Usage:^3 sv_cmd setflag #client_id countrycode[0-249]");
+                       return;
+               }
+       }
+}
+
+void GameCommand_setrank(int request, int argc)
+{
+       switch (request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       entity client;
+                       float accepted;
+                       
+                       client = GetFilteredEntity(argv(1));
+                       accepted = VerifyClientEntity(client, false, false);
+
+                       if (accepted <= 0)
+                       {
+                               LOG_INFO("^1ERROR^7: Couldn't set player rank");
+                               LOG_HELP("Usage:^3 sv_cmd setrank #client_id rank");
+                               return;
+                       }
+                       
+                       client.rank = strzone(argv(2));
+                       LOG_INFO("^2SUCCESS^7: Player rank set!");
+                       return;
+               }
+               default:
+                       LOG_INFOF("Incorrect parameters for ^2%s^7", argv(0));
+               case CMD_REQUEST_USAGE:
+               {
+                       LOG_HELP("Usage:^3 sv_cmd setrank #client_id #rank");
+                       return;
+               }
+       }
+}
+
 void GameCommand_moveplayer(int request, int argc)
 {
        switch (request)
@@ -1193,6 +1354,38 @@ void GameCommand_nospectators(int request)
        }
 }
 
+void GameCommand_printplayer(int request, int argc)
+{
+       switch (request)
+        {
+                       case CMD_REQUEST_COMMAND:
+                       {
+                       entity player = GetIndexedEntity(argc, 1);
+                                               if (player.playerid)
+                                               {
+                                                       GameLogEcho(strcat(
+                                                                                       strcat(
+                                                                                                       ":playerinfo:", ftos(player.playerid),
+                                                                                                       ":", ftos(etof(player)),
+                                                                                                       ":", ftos(CS_CVAR(player).cvar_cl_allow_uidtracking),
+                                                                                                       ":", ftos(CS_CVAR(player).cvar_cl_allow_uid2name)),
+                                                                                       strcat(
+                                                                                                       ":", ftos(CS_CVAR(player).cvar_cl_allow_uidranking),
+                                                                                                       ":", ((IS_REAL_CLIENT(player)) ? GameLog_ProcessIP(player.netaddress) : "bot"),
+                                                                                                       ":", player.crypto_idfp,
+                                                                                                       ":", playername(player.netname, player.team, false))));
+                                               }
+                                       return;
+                               }
+                       default:
+                               case CMD_REQUEST_USAGE:
+                               {
+                                       LOG_HELP("Usage:^3 sv_cmd printplayer <player_entity_id>");
+                                               return;
+                               }
+               }
+}
+
 void GameCommand_printstats(int request)
 {
        switch (request)
@@ -1638,7 +1831,7 @@ void GameCommand_unlockteams(int request)
                        if (teamplay)
                        {
                                lockteams = 0;
-                               bprint("^1The teams are now unlocked.\n");
+                               bprint("\{1}^1The teams are now unlocked.\n");
                        }
                        else
                        {
@@ -1751,17 +1944,22 @@ SERVER_COMMAND(extendmatchtime, "Increase the timelimit value incrementally") {
 SERVER_COMMAND(gametype, "Simple command to change the active gametype") { GameCommand_gametype(request, arguments); }
 SERVER_COMMAND(gettaginfo, "Get specific information about a weapon model") { GameCommand_gettaginfo(request, arguments); }
 SERVER_COMMAND(gotomap, "Simple command to switch to another map") { GameCommand_gotomap(request, arguments); }
+SERVER_COMMAND(ircmsg, "Chat message to be sent by IRC bots") { GameCommand_ircmsg(request, arguments, command); }
 SERVER_COMMAND(lockteams, "Disable the ability for players to switch or enter teams") { GameCommand_lockteams(request); }
 SERVER_COMMAND(make_mapinfo, "Automatically rebuild mapinfo files") { GameCommand_make_mapinfo(request); }
 SERVER_COMMAND(moveplayer, "Change the team/status of a player") { GameCommand_moveplayer(request, arguments); }
 SERVER_COMMAND(nospectators, "Automatically remove spectators from a match") { GameCommand_nospectators(request); }
+SERVER_COMMAND(printplayer, "Print information about a player") { GameCommand_printplayer(request, arguments); }
 SERVER_COMMAND(printstats, "Dump eventlog player stats and other score information") { GameCommand_printstats(request); }
 SERVER_COMMAND(radarmap, "Generate a radar image of the map") { GameCommand_radarmap(request, arguments); }
 SERVER_COMMAND(reducematchtime, "Decrease the timelimit value incrementally") { GameCommand_reducematchtime(request); }
 SERVER_COMMAND(resetmatch, "Soft restart the game without changing teams; goes back to warmup if enabled") { GameCommand_resetmatch(request); }
 SERVER_COMMAND(setbots, "Adjust how many bots are in the match") { GameCommand_setbots(request, arguments); }
+SERVER_COMMAND(setflag, "Set client flag") { GameCommand_setflag(request, arguments); }
+SERVER_COMMAND(setrank, "Set client rank") { GameCommand_setrank(request, arguments); }
 SERVER_COMMAND(shuffleteams, "Randomly move players to different teams") { GameCommand_shuffleteams(request); }
 SERVER_COMMAND(stuffto, "Send a command to be executed on a client") { GameCommand_stuffto(request, arguments); }
+SERVER_COMMAND(teamname, "Set team name") { GameCommand_teamname(request, arguments); }
 SERVER_COMMAND(trace, "Various debugging tools with tracing") { GameCommand_trace(request, arguments); }
 SERVER_COMMAND(unlockteams, "Enable the ability for players to switch or enter teams") { GameCommand_unlockteams(request); }
 SERVER_COMMAND(warp, "Choose different level in campaign") { GameCommand_warp(request, arguments); }
index e8c6812c2c4faaf38c380314de00c43a8095cfdd..e27c5fe8a120914b51a59d5228ac9f1405efc650 100644 (file)
@@ -227,7 +227,11 @@ void VoteCount(float first_count)
        Nagger_VoteCountChanged();
 
        // add up all the votes from each connected client
-       FOREACH_CLIENT(IS_REAL_CLIENT(it) || autocvar_sv_vote_debug, {
+       FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_CLIENT(it), {
+               // z411
+               if(vote_target_type == VOTE_TARGET_TEAM && it.team != vote_caller.team) continue;
+               if(vote_target_type == VOTE_TARGET_SINGLE && it != vote_target) continue;
+               
                ++vote_player_count;
                if (IS_PLAYER(it) || INGAME(it)) ++vote_real_player_count;
                switch (it.vote_selection)
@@ -361,6 +365,12 @@ void reset_map(bool is_fake_round_start)
                if (round_handler_IsActive())
                        round_handler_Reset(game_starttime);
        }
+       
+       // for RJZ
+       if (autocvar_rjz_count_shards) {
+               total_shards = 0;
+               send_TotalShardsAll();
+       }
 
        if (shuffleteams_on_reset_map)
        {
@@ -468,8 +478,11 @@ void ReadyRestart_force(bool is_fake_round_start)
        if(!is_fake_round_start && !warmup_stage)
                localcmd("\nsv_hook_warmupend\n");
 
-       // reset the .ready status of all clients (including spectators and bots)
-       FOREACH_CLIENT(true, { it.ready = false; });
+       // reset the .ready status of all players (also spectators)
+       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
+               it.ready = false;
+               Kill_Notification(NOTIF_ONE_ONLY, it, MSG_CENTER, CPID_MISSING_READY);
+       });
        readycount = 0;
        Nagger_ReadyCounted();  // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
 
@@ -491,6 +504,7 @@ void ReadyRestart_force(bool is_fake_round_start)
                FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), { CS(it).allowed_timeouts = autocvar_sv_timeout_number; });
        }
 
+       round_handler_Activate(!warmup_stage);
        if (!sv_ready_restart_after_countdown || warmup_stage)
                reset_map(is_fake_round_start);
 
@@ -557,7 +571,7 @@ void ReadyCount()
                        game_starttime = time;
                        Send_Notification(NOTIF_ALL, NULL, MSG_MULTI, COUNTDOWN_STOP, minplayers);
                        if (!sv_ready_restart_after_countdown) // if we ran reset_map() at start of countdown
-                               FOREACH_CLIENT(IS_PLAYER(it), { GiveWarmupResources(it); });
+                               FOREACH_CLIENT(IS_PLAYER(it), { ResetPlayerResources(it); });
                }
                if (warmup_limit > 0)
                        warmup_limit = -1;
@@ -755,6 +769,8 @@ int VoteCommand_parse(entity caller, string vote_command, string vote_list, floa
                case MUT_VOTEPARSE_UNACCEPTABLE: { return 0; }
        }
 
+       vote_target_type = VOTE_TARGET_ALL;
+       
        switch (first_command) // now go through and parse the proper commands to adjust as needed.
        {
                case "movetoauto":
@@ -796,7 +812,11 @@ int VoteCommand_parse(entity caller, string vote_command, string vote_list, floa
                                if (first_command == "kickban")
                                        command_arguments = strcat(ftos(autocvar_g_ban_default_bantime), " ", ftos(autocvar_g_ban_default_masksize), " ~");
 
-                               vote_parsed_command = strcat(first_command, " # ", ftos(etof(victim)), " ", command_arguments);
+                               if (first_command == "kick") // z411 : Use our kick implementation - kind of hacky...
+                                       vote_parsed_command = strcat("defer 2 \"sv_cmd kickkick # ", ftos(etof(victim)), " ", command_arguments, "\"");
+                               else
+                                       vote_parsed_command = strcat("defer 2 \"", first_command, " # ", ftos(etof(victim)), " ", command_arguments, "\"");
+                               
                                vote_parsed_display = sprintf("^1%s #%d ^7%s^1 %s", first_command, etof(victim), victim.netname, reason);
                        }
                        else
@@ -814,11 +834,27 @@ int VoteCommand_parse(entity caller, string vote_command, string vote_list, floa
                {
                        vote_command = ValidateMap(argv(startpos + 1), caller);
                        if (!vote_command)  return -1;
-                       vote_parsed_command = strcat("gotomap ", vote_command);
-                       vote_parsed_display = strzone(strcat("^1", vote_parsed_command));
+                       vote_parsed_command = strcat("defer 2 \"gotomap ", vote_command, "\"");
+                       vote_parsed_display = strzone(strcat("^1gotomap ", vote_command));
 
                        break;
                }
+               
+               // z411 team calls
+               case "teamname":
+               {
+                       if (teamplay && Team_IsValidTeam(caller.team)) {
+                               vote_target_type = VOTE_TARGET_TEAM;
+                       
+                               string tmname = strtolower(Static_Team_ColorName(caller.team));
+                               string newname = argv(startpos + 1);
+                               
+                               vote_parsed_command = strcat(first_command, " ", tmname, " \"", newname, "\"");
+                               vote_parsed_display = strzone(strcat("^3(Team) ^1", first_command, " ^2", newname));
+                       } else { print_to(caller, "vcall: Not in a team\n"); return 0; }
+                       
+                       break;
+               }
 
                // TODO: replicate the old behaviour of being able to vote for maps from different modes on multimode servers (possibly support it in gotomap too)
                // maybe fallback instead of aborting if map name is invalid?
@@ -862,11 +898,24 @@ int VoteCommand_parse(entity caller, string vote_command, string vote_list, floa
                        break;
                }
 
-               case "restart":
+               case "gg":
+               case "shuffleteams":
+               case "endmatch":
                {
                        // add a delay so that vote result can be seen and announcer can be heard
                        // if the vote is accepted
-                       vote_parsed_command = strcat("defer 1 ", vote_command);
+                       vote_parsed_command = strcat("defer 2 ", vote_command);
+                       vote_parsed_display = strzone(strcat("^1", vote_command));
+                       
+                       break;
+               }
+
+               case "reset":
+               case "restart": // re-direct all match restarting to resetmatch
+                       vote_command = "resetmatch"; // fall-through
+               case "resetmatch":
+               {
+                       vote_parsed_command = strcat("defer 2 ", vote_command);
                        vote_parsed_display = strzone(strcat("^1", vote_command));
 
                        break;
@@ -879,7 +928,7 @@ int VoteCommand_parse(entity caller, string vote_command, string vote_list, floa
                                return -1;
                        }
 
-                       vote_parsed_command = vote_command;
+                       vote_parsed_command = strcat("defer 2 ", vote_command);
                        vote_parsed_display = strzone(strcat("^1", vote_command));
                        break;
                }
index 509d4d233ab559f2b590ca54b9fda25a93d2c7e3..63f624870081c269fc936ec32a9880a6d18be661 100644 (file)
@@ -38,6 +38,11 @@ const float VOTE_NULL = 0;
 const float VOTE_NORMAL = 1;
 const float VOTE_MASTER = 2;
 
+// z411 vote targets
+const float VOTE_TARGET_ALL = 0;
+const float VOTE_TARGET_TEAM = 1;
+const float VOTE_TARGET_SINGLE = 2;
+
 // global vote information declarations
 entity vote_caller;         // original caller of the current vote
 string vote_caller_name;    // name of the vote caller
@@ -47,6 +52,8 @@ int vote_accept_count;      // total amount of players who accept the vote (coun
 int vote_reject_count;      // same as above, but rejected
 int vote_abstain_count;     // same as above, but abstained
 int vote_needed_overall;    // total amount of players NEEDED for a vote to pass (based on sv_vote_majority_factor)
+float vote_target_type; // z411
+entity vote_target; // z411
 .bool vote_master;          // flag for if the player has vote master privileges
 .float vote_waittime;       // flag for how long the player must wait before they can vote again
 .int vote_selection;        // flag for which vote selection the player has made (See VOTE_SELECT_*)
index d5a9a20c760d352a7d6631ed2530eba9cf2faad4..bdd165b9113de70bbaa79cef02103916d826d09b 100644 (file)
@@ -124,6 +124,7 @@ void LogDeath(string mode, int deathtype, entity killer, entity killed)
 
 void Obituary_SpecialDeath(
        entity notif_target,
+       entity attacker,
        float murder,
        int deathtype,
        string s1, string s2, string s3,
@@ -165,10 +166,15 @@ void Obituary_SpecialDeath(
                        f1, f2, f3, 0
                );
        }
+       
+       if(deathtype == DEATH_TELEFRAG.m_id) {
+               Give_Medal(attacker, TELEFRAG);
+       }
 }
 
 float Obituary_WeaponDeath(
        entity notif_target,
+       entity attacker,
        float murder,
        int deathtype,
        string s1, string s2, string s3,
@@ -201,6 +207,20 @@ float Obituary_WeaponDeath(
                        s1, s2, s3, "",
                        f1, f2, 0, 0
                );
+               
+               // z411 special medals
+               if(attacker) {
+                       switch(death_message) {
+                               case WEAPON_SHOTGUN_MURDER_SLAP:
+                                       if(!cvar("g_melee_only")) { // don't spam humiliation if we're in melee_only mode
+                                               Give_Medal(attacker, HUMILIATION);
+                                       }
+                                       break;
+                               case WEAPON_ELECTRO_MURDER_COMBO:
+                                       Give_Medal(attacker, ELECTROBITCH);
+                                       break;
+                       }
+               }
        }
        else
        {
@@ -272,7 +292,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                {
                        if(deathtype == DEATH_TEAMCHANGE.m_id || deathtype == DEATH_AUTOTEAMCHANGE.m_id)
                        {
-                               Obituary_SpecialDeath(targ, false, deathtype, targ.netname, deathlocation, "", targ.team, 0, 0);
+                               Obituary_SpecialDeath(targ, NULL, false, deathtype, targ.netname, deathlocation, "", targ.team, 0, 0);
                        }
                        else
                        {
@@ -280,26 +300,27 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                                {
                                        case DEATH_MIRRORDAMAGE:
                                        {
-                                               Obituary_SpecialDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0, 0);
+                                               Obituary_SpecialDeath(targ, NULL, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0, 0);
                                                break;
                                        }
                                        case DEATH_HURTTRIGGER:
-                                               Obituary_SpecialDeath(targ, false, deathtype, targ.netname, inflictor.message, deathlocation, CS(targ).killcount, 0, 0);
+                                               Obituary_SpecialDeath(targ, NULL, false, deathtype, targ.netname, inflictor.message, deathlocation, CS(targ).killcount, 0, 0);
                                                break;
                                        default:
                                        {
-                                               Obituary_SpecialDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0, 0);
+                                               Obituary_SpecialDeath(targ, NULL, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0, 0);
                                                break;
                                        }
                                }
                        }
                }
-               else if (!Obituary_WeaponDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0))
+               else if (!Obituary_WeaponDeath(targ, NULL, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0))
                {
                        backtrace("SUICIDE: what the hell happened here?\n");
                        return;
                }
                LogDeath("suicide", deathtype, targ, targ);
+               Send_Notification(NOTIF_ONE, targ, MSG_ANNCE, ANNCE_SUICIDE);
                if(deathtype != DEATH_AUTOTEAMCHANGE.m_id) // special case: don't negate frags if auto switched
                        GiveFrags(attacker, targ, -1, deathtype, weaponentity);
        }
@@ -318,7 +339,9 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
 
                        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_name);
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(targ.team, INFO_DEATH_TEAMKILL), targ.netname, attacker_name, deathlocation, CS(targ).killcount);
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(targ.team, INFO_DEATH_TEAMKILL),
+                               playername(targ.netname, targ.team, true), playername(attacker_name, attacker.team, true),
+                               deathlocation, CS(targ).killcount);
 
                        // In this case, the death message will ALWAYS be "foo was betrayed by bar"
                        // No need for specific death/weapon messages...
@@ -332,12 +355,12 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                        CS(attacker).killcount = CS(attacker).killcount + 1;
 
                        attacker.killsound += 1;
-
+                       
                        // TODO: improve SPREE_ITEM and KILL_SPREE_LIST
                        // these 2 macros are spread over multiple files
                        #define SPREE_ITEM(counta,countb,center,normal,gentle) \
                                case counta: \
-                                       Send_Notification(NOTIF_ONE, attacker, MSG_ANNCE, ANNCE_KILLSTREAK_##countb); \
+                                       Give_Medal(attacker, KILLSTREAK_##countb); \
                                        if (!warmup_stage) \
                                                PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
                                        break;
@@ -353,6 +376,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                        {
                                checkrules_firstblood = true;
                                notif_firstblood = true; // modify the current messages so that they too show firstblood information
+                               Give_Medal(attacker, FIRSTBLOOD);
                                PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
                                PlayerStats_GameReport_Event_Player(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
 
@@ -365,6 +389,12 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                                kill_count_to_attacker = CS(attacker).killcount;
                                kill_count_to_target = 0;
                        }
+                       
+                       // Excellent check
+                       if(attacker.lastkill && attacker.lastkill > time - autocvar_g_medals_excellent_time) {
+                               Give_Medal(attacker, EXCELLENT);
+                       }
+                       attacker.lastkill = time;
 
                        if(targ.istypefrag)
                        {
@@ -417,8 +447,8 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                        if(deathtype == DEATH_BUFF.m_id)
                                f3 = buff_FirstFromFlags(attacker).m_id;
 
-                       if (!Obituary_WeaponDeath(targ, true, deathtype, targ.netname, attacker_name, deathlocation, CS(targ).killcount, kill_count_to_attacker))
-                               Obituary_SpecialDeath(targ, true, deathtype, targ.netname, attacker_name, deathlocation, CS(targ).killcount, kill_count_to_attacker, f3);
+                       if (!Obituary_WeaponDeath(targ, attacker, true, deathtype, playername(targ.netname, targ.team, true), playername(attacker_name, attacker.team, true), deathlocation, CS(targ).killcount, kill_count_to_attacker))
+                               Obituary_SpecialDeath(targ, attacker, true, deathtype, playername(targ.netname, targ.team, true), playername(attacker_name, attacker.team, true), deathlocation, CS(targ).killcount, kill_count_to_attacker, f3);
                }
        }
 
@@ -434,8 +464,8 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                        // and there will be a REAL DEATH_VOID implementation which mappers will use.
                        case DEATH_HURTTRIGGER:
                        {
-                               Obituary_SpecialDeath(targ, false, deathtype,
-                                       targ.netname,
+                               Obituary_SpecialDeath(targ, NULL, false, deathtype,
+                                       playername(targ.netname, targ.team, true),
                                        inflictor.message,
                                        deathlocation,
                                        CS(targ).killcount,
@@ -446,8 +476,8 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
 
                        case DEATH_CUSTOM:
                        {
-                               Obituary_SpecialDeath(targ, false, deathtype,
-                                       targ.netname,
+                               Obituary_SpecialDeath(targ, NULL, false, deathtype,
+                                       playername(targ.netname, targ.team, true),
                                        ((strstrofs(deathmessage, "%", 0) < 0) ? strcat("%s ", deathmessage) : deathmessage),
                                        deathlocation,
                                        CS(targ).killcount,
@@ -458,12 +488,13 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
 
                        default:
                        {
-                               Obituary_SpecialDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0, 0);
+                               Obituary_SpecialDeath(targ, NULL, false, deathtype, playername(targ.netname, targ.team, true), deathlocation, "", CS(targ).killcount, 0, 0);
                                break;
                        }
                }
 
                LogDeath("accident", deathtype, targ, targ);
+               Send_Notification(NOTIF_ONE, targ, MSG_ANNCE, ANNCE_ACCIDENT);
                GiveFrags(targ, targ, -1, deathtype, weaponentity);
 
                if(GameRules_scoring_add(targ, SCORE, 0) == -5)
index 09b80eea1de36cbed4100ab0952a3ff389324606..2e278d83a4a1358253fb8d433ba6b541e7c67e07 100644 (file)
@@ -64,6 +64,7 @@ int impressive_hits;
 .float spawnshieldtime;
 
 .int totalfrags;
+.float lastkill;
 
 .bool canteamdamage;
 
@@ -89,6 +90,7 @@ void LogDeath(string mode, int deathtype, entity killer, entity killed);
 
 void Obituary_SpecialDeath(
        entity notif_target,
+       entity attacker,
        float murder,
        int deathtype,
        string s1, string s2, string s3,
@@ -97,6 +99,7 @@ void Obituary_SpecialDeath(
 float w_deathtype;
 float Obituary_WeaponDeath(
        entity notif_target,
+       entity target,
        float murder,
        int deathtype,
        string s1, string s2, string s3,
index a949da10b3ca150a1911c44622bc6c11396a2614..ff52be95bca21ad992962f4a3536306081412894 100644 (file)
@@ -6,6 +6,7 @@
 #include <common/weapons/_all.qh>
 #include <server/command/banning.qh>
 #include <server/main.qh>
+#include <common/notifications/all.qh>
 
 /*
  * Protocol of online ban list:
@@ -579,12 +580,20 @@ float Ban_Insert(string ip, float bantime, string reason, float dosync)
        return true;
 }
 
+void Ban_KickClient(entity client, string reason)
+{
+       sprint(client, strcat("Kicked: ", reason, "\n"));
+       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_KICK, client.netname);
+       dropclient(client);
+}
+
 void Ban_KickBanClient(entity client, float bantime, float masksize, string reason)
 {
        string ip, id;
        if(!Ban_GetClientIP(client))
        {
                sprint(client, strcat("Kickbanned: ", reason, "\n"));
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_KICK, client.netname);
                dropclient(client);
                return;
        }
index 330d8b7dff1e8c509ee6b419fddc14442423ec2e..0e9dff87acaaf59f902db6d03b9607382b0619d9 100644 (file)
@@ -7,6 +7,7 @@ float Ban_MaybeEnforceBanOnce(entity client);
 float BanCommand(string command);
 
 float Ban_Insert(string ip, float bantime, string reason, float dosync);
+void Ban_KickClient(entity client, string reason);
 void Ban_KickBanClient(entity client, float bantime, float masksize, string reason);
 void Ban_View();
 float Ban_Delete(float i);
index b0b68fd920791b06b850cc3dabef1f047d78e844..86ede0b7bd20cd481dc0830905737dfb188d70d6 100644 (file)
@@ -257,6 +257,8 @@ void Item_Respawn(entity this)
 
 void Item_RespawnCountdown(entity this)
 {
+       if(game_timeout) { this.nextthink = time + 1; return; }
+       
        if(this.item_respawncounter >= ITEM_RESPAWN_TICKS)
        {
                if(this.waypointsprite_attached)
@@ -266,7 +268,11 @@ void Item_RespawnCountdown(entity this)
        else
        {
                this.nextthink = time + 1;
-               this.item_respawncounter += 1;
+               this.item_respawncounter = floor((time - game_starttime) - (this.scheduledrespawntime - ITEM_RESPAWN_TICKS)) + 1;
+               //this.item_respawncounter += 1;
+               //LOG_INFOF("Respawncounter: %d", this.item_respawncounter);
+               if(this.item_respawncounter < 1) return;
+               
                if(this.item_respawncounter == 1)
                {
                        do {
@@ -315,12 +321,14 @@ void Item_RespawnCountdown(entity this)
 
 void Item_RespawnThink(entity this)
 {
-       this.nextthink = time;
+       this.nextthink = time + 1;
        if(this.origin != this.oldorigin)
                ItemUpdate(this);
-
-       if(time >= this.wait)
+       
+       if(!game_timeout && time - game_starttime >= this.wait)
                Item_Respawn(this);
+       
+       //LOG_INFOF("time until respawn %d", (this.wait) - (time - game_starttime));
 }
 
 void Item_ScheduleRespawnIn(entity e, float t)
@@ -329,9 +337,12 @@ void Item_ScheduleRespawnIn(entity e, float t)
        if ((Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS) || MUTATOR_CALLHOOK(Item_ScheduleRespawn, e, t)) && (t - ITEM_RESPAWN_TICKS) > 0)
        {
                setthink(e, Item_RespawnCountdown);
-               e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
-               e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
+               //e.nextthink = time - timeout_total_time + max(0, t - ITEM_RESPAWN_TICKS);
+               //e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
+               e.nextthink = time;
+               e.scheduledrespawntime = time - game_starttime + t;
                e.item_respawncounter = 0;
+               
                if(Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
                {
                        t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
@@ -343,8 +354,8 @@ void Item_ScheduleRespawnIn(entity e, float t)
        {
                setthink(e, Item_RespawnThink);
                e.nextthink = time;
-               e.scheduledrespawntime = time + t;
-               e.wait = time + t;
+               e.scheduledrespawntime = time - game_starttime + t;
+               e.wait = time - game_starttime + t;
 
                if(Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
                {
@@ -557,6 +568,13 @@ bool Item_GiveTo(entity item, entity player)
        pickedup |= Item_GiveAmmoTo(item, player, RES_CELLS, g_pickup_cells_max);
        pickedup |= Item_GiveAmmoTo(item, player, RES_PLASMA, g_pickup_plasma_max);
        pickedup |= Item_GiveAmmoTo(item, player, RES_FUEL, g_pickup_fuel_max);
+       
+       // for RJZ
+       if (autocvar_rjz_count_shards && !warmup_stage && item.itemdef == ITEM_ArmorSmall) {
+               total_shards++;
+               send_TotalShardsAll();
+       }
+       
        if (item.itemdef.instanceOfWeaponPickup)
        {
                WepSet w, wp;
index 46fb4ede17e4cc4fdb67d82ae8149fd4eee31bd9..a2a4ca7dbf8f5ef00ae2cec3522d6fa1210bfb25 100644 (file)
@@ -868,6 +868,7 @@ MUTATOR_HOOKABLE(FireBullet_Hit, EV_FireBullet_Hit);
 MUTATOR_HOOKABLE(FixPlayermodel, EV_FixPlayermodel);
 
 /** Return error to play frag remaining announcements */
+MUTATOR_HOOKABLE(Scores_AnnounceLeads, EV_NO_ARGS);
 MUTATOR_HOOKABLE(Scores_CountFragsRemaining, EV_NO_ARGS);
 
 #define EV_GrappleHookThink(i, o) \
index d47aad441ec4add47fcbd7cba5eb8c39b5b0dc75..176efb25d0f1f12c0d95441e9c8063c0d45186aa 100644 (file)
@@ -5,11 +5,15 @@
 #include <common/util.qh>
 #include <server/campaign.qh>
 #include <server/command/vote.qh>
+#include <server/weapons/accuracy.qh>
 #include <server/scores.qh>
 #include <server/world.qh>
 
 void round_handler_Think(entity this)
 {
+       if (!this.isactive) return;
+       if (game_timeout) { this.nextthink = time + 1; return; }
+
        if (intermission_running)
        {
                round_handler_Reset(0);
@@ -47,6 +51,7 @@ void round_handler_Think(entity this)
                                this.cnt = 0;
                                this.round_endtime = (this.round_timelimit) ? time + this.round_timelimit : 0;
                                this.nextthink = time;
+                               FOREACH_CLIENT(IS_PLAYER(it), { roundaccuracy_clear(it); });
                                rounds_played++;
                                if (this.roundStart) this.roundStart();
                                return;
@@ -65,6 +70,7 @@ void round_handler_Think(entity this)
                if (this.canRoundEnd())
                {
                        // schedule a new round
+                       round_delaytime = time;
                        this.wait = true;
                        this.nextthink = time + this.delay;
                }
@@ -102,8 +108,7 @@ void round_handler_Spawn(bool() canRoundStart_func, bool() canRoundEnd_func, voi
                return;
        }
        entity this = round_handler = new_pure(round_handler);
-
-       setthink(this, round_handler_FirstThink);
+       
        this.canRoundStart = canRoundStart_func;
        this.canRoundEnd = canRoundEnd_func;
        this.roundStart = roundStart_func;
@@ -114,6 +119,20 @@ void round_handler_Spawn(bool() canRoundStart_func, bool() canRoundEnd_func, voi
        ScoreInfo_SetLabel_PlayerScore(SP_ROUNDS_PL, "rounds_pl", 0);
 }
 
+void round_handler_Activate(bool active) {
+       if (round_handler) {
+               entity this = round_handler;
+       
+               this.isactive = active;
+               if(active) {
+                       setthink(this, round_handler_FirstThink);
+                       this.nextthink = time;
+               } else {
+                       round_starttime = -1;
+               }
+       }
+}
+
 void round_handler_Reset(float next_think)
 {
        entity this = round_handler;
index 5979eb5c33f810faeb55f2add99f7574533fc121..01288ab64620d1e089ee7a6c7595495a306b1f36 100644 (file)
@@ -1,6 +1,7 @@
 #pragma once
 
 entity round_handler;
+.bool isactive;
 .float delay; // stores delay from round end to countdown start
 .float count; // stores initial number of the countdown
 .bool wait; // it's set to true when round ends, to false when countdown starts
@@ -15,9 +16,10 @@ entity round_handler;
 void round_handler_Init(float the_delay, float the_count, float the_round_timelimit);
 void round_handler_Spawn(bool() canRoundStart_func, bool() canRoundEnd_func, void() roundStart_func);
 void round_handler_Reset(float next_think);
+void round_handler_Activate(bool active);
 void round_handler_Remove();
 
-#define round_handler_IsActive() (round_handler != NULL)
+#define round_handler_IsActive() (round_handler != NULL && round_handler.isactive)
 #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)
index 5e1c8d9db567b67fd8f3635803cd6dd4266fbd25..83c5d5ee5339e96aaef7405e4206837655767d6f 100644 (file)
@@ -292,8 +292,8 @@ float PlayerScore_Clear(entity player)
        sk = CS(player).scorekeeper;
        FOREACH(Scores, true, {
                if(sk.(scores(it)) != 0)
-                       if(scores_label(it) != "")
-                               sk.SendFlags |= BIT(i % 16);
+                       //if(scores_label(it) != "")
+                       sk.SendFlags |= (2 ** (i % 16));
                if(i != SP_ELO.m_id)
                        sk.(scores(it)) = 0;
        });
@@ -310,8 +310,8 @@ void Score_ClearAll()
                if (!sk) continue;
                FOREACH(Scores, true, {
                        if(sk.(scores(it)) != 0)
-                               if(scores_label(it) != "")
-                                       sk.SendFlags |= BIT(i % 16);
+                               //if(scores_label(it) != "")
+                               sk.SendFlags |= (2 ** (i % 16));
                        if(i != SP_ELO.m_id)
                                sk.(scores(it)) = 0;
                });
@@ -324,8 +324,8 @@ void Score_ClearAll()
                for(int j = 0; j < MAX_TEAMSCORE; ++j)
                {
                        if(sk.(teamscores(j)) != 0)
-                               if(teamscores_label(j) != "")
-                                       sk.SendFlags |= BIT(j);
+                               //if(teamscores_label(j) != "")
+                               sk.SendFlags |= (2 ** j);
                        sk.(teamscores(j)) = 0;
                }
        }
@@ -372,8 +372,8 @@ float PlayerScore_Add(entity player, PlayerScoreField scorefield, float score)
        {
                return s.(scores(scorefield));
        }
-       if(scores_label(scorefield) != "")
-               s.SendFlags |= BIT(scorefield.m_id % 16);
+       //if(scores_label(scorefield) != "")
+       s.SendFlags |= (2 ** (scorefield.m_id % 16));
        if(!warmup_stage)
                PlayerStats_GameReport_Event_Player(s.owner, strcat(PLAYERSTATS_TOTAL, scores_label(scorefield)), score);
        s.(scores(scorefield)) += score;
@@ -441,6 +441,24 @@ float PlayerScore_Compare(entity t1, entity t2, bool strict)
        return result;
 }
 
+bool Score_NewLeader()
+{
+       if(teamplay) {
+               if (WinningConditionHelper_winnerteam != WinningConditionHelper_winnerteam_last && (WinningConditionHelper_secondteam || WinningConditionHelper_equality))
+               {
+                       WinningConditionHelper_winnerteam_last = WinningConditionHelper_winnerteam;
+                       return true;
+               }
+       } else {
+               if (WinningConditionHelper_winner != WinningConditionHelper_winner_last && (WinningConditionHelper_second || WinningConditionHelper_equality))
+               {
+                       WinningConditionHelper_winner_last = WinningConditionHelper_winner;
+                       return true;
+               }
+       }
+       return false;
+}
+
 void WinningConditionHelper(entity this)
 {
        float c;
@@ -543,7 +561,15 @@ void WinningConditionHelper(entity this)
 
                WinningConditionHelper_equality = (PlayerScore_Compare(winnerscorekeeper, secondscorekeeper, false) == 0);
                if(WinningConditionHelper_equality)
+               {
+                       WinningConditionHelper_equality_one = WinningConditionHelper_winner;
+                       WinningConditionHelper_equality_two = WinningConditionHelper_second;
                        WinningConditionHelper_winner = WinningConditionHelper_second = NULL;
+               }
+               else
+               {
+                       WinningConditionHelper_equality_one = WinningConditionHelper_equality_two = NULL;
+               }
 
                WinningConditionHelper_topscore = winnerscorekeeper.scores_primary;
                WinningConditionHelper_secondscore = secondscorekeeper.scores_primary;
index 2b6ea4881045808340260607aaabd596032a6a5f..8738d3a2df79e97a49742d17e809b68e44459dc1 100644 (file)
@@ -107,10 +107,14 @@ void WinningConditionHelper(entity this);
 float WinningConditionHelper_topscore;      ///< highest score
 float WinningConditionHelper_secondscore;   ///< second highest score
 float WinningConditionHelper_winnerteam;    ///< the color of the winning team, or -1 if none
+float WinningConditionHelper_winnerteam_last;
 float WinningConditionHelper_secondteam;    ///< the color of the second team, or -1 if none
 float WinningConditionHelper_equality;      ///< we have no winner
 entity WinningConditionHelper_winner;       ///< the winning player, or NULL if none
 entity WinningConditionHelper_second;       ///< the second player, or NULL if none
+entity WinningConditionHelper_winner_last;
+entity WinningConditionHelper_equality_one;
+entity WinningConditionHelper_equality_two;
 float WinningConditionHelper_lowerisbetter; ///< lower is better, duh
 float WinningConditionHelper_zeroisworst;   ///< zero is worst, duh
 #define WINNINGCONDITIONHELPER_LOWERISBETTER_WORST 999999999
@@ -138,3 +142,6 @@ string GetTeamScoreString(float tm, float shortString);
  * nospectators: exclude spectators
  */
 entity PlayerScore_Sort(.float field, int teams, bool strict, bool nospectators);
+
+// z411
+bool Score_NewLeader();
index 1cfdbf4a0538da331630210cdfbc92a4ef4333ec..8ab200b8bde816d60de4c1e039c9808b2c0fd236 100644 (file)
@@ -31,6 +31,7 @@ const int TEAM_NOT_ALLOWED = -1;
 .int m_team_balance_state; ///< Holds the state of the team balance entity.
 .entity m_team_balance_team[NUM_TEAMS]; ///< ???
 
+.string m_team_name; // z411 team name
 .float m_team_score; ///< The score of the team.
 .int m_num_players; ///< Number of players (both humans and bots) in a team.
 .int m_num_bots; ///< Number of bots in a team.
@@ -72,6 +73,16 @@ entity Team_GetTeam(int team_num)
        return g_team_entities[Team_TeamToIndex(team_num) - 1];
 }
 
+string Team_GetTeamName(entity team_ent)
+{
+       return team_ent.m_team_name;
+}
+
+void Team_SetTeamName(entity team_ent, string name)
+{
+       team_ent.m_team_name = name;
+}
+
 float Team_GetTeamScore(entity team_ent)
 {
        return team_ent.m_team_score;
@@ -92,6 +103,16 @@ void Team_SetNumberOfAlivePlayers(entity team_ent, int number)
        team_ent.m_num_players_alive = number;
 }
 
+int Team_GetNumberOfPlayers(entity team_ent)
+{
+       return team_ent.m_num_players;
+}
+
+void Team_SetNumberOfPlayers(entity team_ent, int number)
+{
+       team_ent.m_num_players = number;
+}
+
 int Team_GetWinnerAliveTeam()
 {
        int winner = 0;
@@ -234,6 +255,21 @@ bool Player_SetTeamIndex(entity player, int index)
        return true;
 }
 
+entity SpectatorWantsJoin(entity this)
+{
+       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
+               if(it == this) continue;
+               if(it.wants_join) {
+                       LOG_DEBUGF("Player is waiting to join: %s", it.netname);
+                       return it;
+               }
+       });
+
+       // No players waiting to join
+       LOG_DEBUG("No players waiting to join.");
+       return NULL;
+}
+
 bool SetPlayerTeam(entity player, int team_index, int type)
 {
        int old_team_index = Entity_GetTeamIndex(player);
@@ -252,7 +288,18 @@ bool SetPlayerTeam(entity player, int team_index, int type)
                        TeamBalance_AutoBalanceBots();
 
                if (team_index != -1)
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(player.team, INFO_JOIN_PLAY_TEAM), player.netname);
+               {
+                       if (!IS_BOT_CLIENT(player) && IS_QUEUE_NEEDED(player) && !SpectatorWantsJoin(player))
+                       {
+                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(player.team, INFO_JOIN_WANTS_TEAM), player.netname);
+                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_JOIN_PREVENT_QUEUE);
+                               player.wants_join = team_index; // Player queued to join
+                       }
+                       else
+                       {
+                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(player.team, INFO_JOIN_PLAY_TEAM), player.netname);
+                       }
+               }
        }
 
        if (team_index == -1)
@@ -263,6 +310,12 @@ bool SetPlayerTeam(entity player, int team_index, int type)
                        Kill_Notification(NOTIF_ONE_ONLY, player, MSG_CENTER, CPID_IDLING);
                        CS(player).idlekick_lasttimeleft = 0;
                }
+               else if (player.wants_join)
+               {
+                       player.wants_join = 0;
+                       player.team_selected = false;
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_QUEUE, player.netname);
+               }
                else if (!CS(player).just_joined && player.frags != FRAGS_SPECTATOR)
                {
                        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, player.netname);
@@ -657,6 +710,130 @@ int TeamBalance_GetAllowedTeams(entity balance)
        return result;
 }
 
+bool TeamBalance_AreEqual(entity ignore, bool would_leave)
+{
+       entity balance = TeamBalance_CheckAllowedTeams(ignore);
+       TeamBalance_GetTeamCounts(balance, ignore);
+
+       bool equality = true;
+       int total;
+       int prev_total = 0;
+       int bots = 0;
+
+       for(int i = 1; i <= AVAILABLE_TEAMS; ++i)
+       {
+               total = TeamBalance_GetTeamFromIndex(balance, i).m_num_players;
+               bots += TeamBalance_GetTeamFromIndex(balance, i).m_num_bots;
+               if(i > 1 && total != prev_total)
+               {
+                       equality = false;
+                       break;
+               }
+               prev_total = total;
+       }
+       TeamBalance_Destroy(balance);
+
+       // Ignore if there are "ghost" bots that would leave if anyone joined
+       if (would_leave && bots > autocvar_bot_number)
+               return false;
+
+       return equality;
+}
+
+entity remove_countdown;
+entity remove_player;
+int remove_timeleft;
+
+void Remove_Countdown(entity this)
+{
+       if(remove_timeleft <= 0 || TeamBalance_AreEqual(NULL, false))
+       {
+               if(remove_timeleft <= 0)
+               {
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_MOVETOSPEC_REMOVE, playername(remove_player.netname, remove_player.team, true));
+                       PutObserverInServer(remove_player, true, true);
+               }
+
+               Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_REMOVE);
+
+               delete(this);
+               remove_countdown = NULL;
+               remove_player = NULL;
+               remove_timeleft = 0;
+
+               TeamBalance_RemoveExcessPlayers(NULL); // Check again for excess players in case someone also left while in countdown
+               return;
+       }
+
+       --remove_timeleft;
+       this.nextthink = time + 1;
+}
+
+void TeamBalance_RemoveExcessPlayers(entity ignore)
+{
+       if(AVAILABLE_TEAMS != 2 || autocvar_g_campaign) return;
+
+       entity balance = TeamBalance_CheckAllowedTeams(ignore);
+       TeamBalance_GetTeamCounts(balance, ignore);
+
+       int min = 0;
+
+       for(int i = 1; i <= AVAILABLE_TEAMS; ++i)
+       {
+               int cur = TeamBalance_GetTeamFromIndex(balance, i).m_num_players;
+               if(i == 1 || cur < min)
+                       min = cur;
+       }
+
+       for(int tmi = 1; tmi <= AVAILABLE_TEAMS; ++tmi)
+       {
+               int cur = TeamBalance_GetTeamFromIndex(balance, tmi).m_num_players;
+               if(cur > 0 && cur > min) // If this team has excess players
+               {
+                       // Get newest player
+                       int latest_join = 0;
+                       entity latest_join_pl = NULL;
+
+                       FOREACH_CLIENT(IS_REAL_CLIENT(it) || INGAME(it), {
+                               if(it.team == Team_IndexToTeam(tmi) && CS(it).startplaytime > latest_join)
+                               {
+                                       latest_join = CS(it).startplaytime;
+                                       latest_join_pl = it;
+                               }
+                       });
+
+                       // Force player to spectate
+                       if(latest_join_pl)
+                       {
+                               // Send player to spectate
+                               if(autocvar_g_balance_teams_remove_wait)
+                               {
+                                       // Give a warning before moving to spect
+                                       remove_player = latest_join_pl;
+                                       remove_timeleft = autocvar_g_balance_teams_remove_wait;
+
+                                       if (!remove_countdown)
+                                       {
+                                               remove_countdown = new_pure(remove_countdown);
+                                               setthink(remove_countdown, Remove_Countdown);
+                                               remove_countdown.nextthink = time;
+
+                                               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MOVETOSPEC_REMOVE, playername(remove_player.netname, remove_player.team, true), remove_timeleft);
+                                       }
+                               }
+                               else
+                               {
+                                       // Move to spects immediately
+                                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_MOVETOSPEC_REMOVE, latest_join_pl.netname);
+                                       PutObserverInServer(latest_join_pl, true, true);
+                               }
+                       }
+               }
+       }
+
+       TeamBalance_Destroy(balance);
+}
+
 bool TeamBalance_IsTeamAllowed(entity balance, int index)
 {
        if (balance == NULL)
@@ -708,6 +885,10 @@ void TeamBalance_GetTeamCounts(entity balance, entity ignore)
                        {
                                continue;
                        }
+                       if (it.wants_join)
+                       {
+                               continue; // Queued players aren't actually in the game.
+                       }
                        int team_num;
                        // TODO: Reconsider when the player is truly on the team.
                        if (IS_CLIENT(it) || INGAME(it))
index d96b7df4b25e9559172db0f4b741cad32886a9ed..92e56f13cb480d87c47436bfc87989bdbbd2e8ee 100644 (file)
@@ -7,6 +7,9 @@ bool autocvar_teamplay_lockonrestart;
 
 bool autocvar_g_balance_teams;
 bool autocvar_g_balance_teams_prevent_imbalance;
+bool autocvar_g_balance_teams_queue;
+bool autocvar_g_balance_teams_remove;
+int autocvar_g_balance_teams_remove_wait;
 
 string autocvar_g_forced_team_otherwise;
 
@@ -14,6 +17,10 @@ bool lockteams;
 
 .int team_forced; // can be a team number to force a team, or 0 for default action, or -1 for forced spectator
 
+#define IS_QUEUE_NEEDED(ignore) \
+       (teamplay && autocvar_g_balance_teams_queue && !autocvar_g_campaign && AVAILABLE_TEAMS == 2 \
+       && TeamBalance_AreEqual(ignore, true))
+
 // ========================== Global teams API ================================
 
 void Team_InitTeams();
@@ -45,11 +52,13 @@ void Team_SetTeamScore(entity team_ent, float score);
 /// \param[in] team_ent Team entity.
 /// \return Number of alive players in a team.
 int Team_GetNumberOfAlivePlayers(entity team_ent);
+int Team_GetNumberOfPlayers(entity team_ent);
 
 /// \brief Sets the number of alive players in a team.
 /// \param[in,out] team_ent Team entity.
 /// \param[in] number Number of players to set.
 void Team_SetNumberOfAlivePlayers(entity team_ent, int number);
+void Team_SetNumberOfPlayers(entity team_ent, int number);
 
 /// \brief Returns the winner team.
 /// \return Winner team or 0 if 2 or more teams have alive players or -1 if no team has any alive players.
@@ -113,6 +122,8 @@ enum
        TEAM_CHANGE_SPECTATOR = 4 ///< Player is joining spectators. //TODO: Remove?
 };
 
+entity SpectatorWantsJoin(entity this);
+
 /// \brief Sets the team of the player.
 /// \param[in,out] player Player to adjust.
 /// \param[in] team_index Index of the team to set.
@@ -183,6 +194,9 @@ void TeamBalance_Destroy(entity balance);
 /// \return Bitmask of allowed teams.
 int TeamBalance_GetAllowedTeams(entity balance);
 
+bool TeamBalance_AreEqual(entity ignore, bool would_leave);
+void TeamBalance_RemoveExcessPlayers(entity ignore);
+
 /// \brief Returns whether the team change to the specified team is allowed.
 /// \param[in] balance Team balance entity.
 /// \param[in] index Index of the team.
index a09719f25416fad9b62461f913660bf626112ff2..2b00034205f9dd8c46c51b6db3562300aa3b778a 100644 (file)
@@ -3,6 +3,7 @@
 #include <common/constants.qh>
 #include <common/net_linked.qh>
 #include <common/teams.qh>
+#include <common/gamemodes/gamemode/duel/duel.qh>
 #include <common/util.qh>
 #include <common/weapons/_all.qh>
 #include <server/client.qh>
@@ -25,6 +26,12 @@ bool accuracy_send(entity this, entity to, int sf)
        entity a = this.owner;
        if (IS_SPEC(a)) a = a.enemy;
        a = CS(a).accuracy;
+       
+       // z411 send entity number
+       if(g_duel)
+               WriteByte(MSG_ENTITY, etof(a.owner));
+       else
+               WriteByte(MSG_ENTITY, 0);
 
        if (to != a.owner)
                if (!autocvar_sv_accuracy_data_share && !CS_CVAR(a.owner).cvar_cl_accuracy_data_share)
@@ -32,10 +39,20 @@ bool accuracy_send(entity this, entity to, int sf)
        // note: zero sendflags can never be sent... so we can use that to say that we send no accuracy!
        WriteInt24_t(MSG_ENTITY, sf);
        if (sf == 0) return true;
+       
        // note: we know that client and server agree about SendFlags...
        int f = 1;
        for (int w = 0; w <= WEP_LAST - WEP_FIRST; ++w) {
-               if (sf & f) WriteByte(MSG_ENTITY, accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w]));
+               if (sf & f) {
+                       if(g_duel) {
+                               WriteByte(MSG_ENTITY, a.accuracy_frags[w]);
+                               WriteShort(MSG_ENTITY, a.accuracy_hit[w]);
+                               WriteShort(MSG_ENTITY, a.accuracy_cnt_hit[w]);
+                               WriteShort(MSG_ENTITY, a.accuracy_cnt_fired[w]);
+                       } else {
+                               WriteByte(MSG_ENTITY, accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w]));
+                       }
+               }
                f = (f == 0x800000) ? 1 : f * 2;
        }
        return true;
@@ -45,14 +62,17 @@ bool accuracy_send(entity this, entity to, int sf)
 void accuracy_init(entity e)
 {
        entity a = CS(e).accuracy = new_pure(accuracy);
+       e.roundaccuracy = new_pure(accuracy);
        a.owner = e;
-       a.drawonlytoclient = e;
+       if(!g_duel) // z411
+               a.drawonlytoclient = e;
        Net_LinkEntity(a, false, 0, accuracy_send);
 }
 
 void accuracy_free(entity e)
 {
        delete(CS(e).accuracy);
+       delete(e.roundaccuracy);
 }
 
 void accuracy_reset(entity e)
@@ -80,33 +100,58 @@ void accuracy_resend(entity e)
 //.float hit_time;
 .float fired_time;
 
+void roundaccuracy_clear(entity this)
+{
+       if (IS_INDEPENDENT_PLAYER(this)) return;
+       entity ra = this.roundaccuracy;
+       
+       for (int w = 0; w <= WEP_LAST - WEP_FIRST; ++w) {
+               ra.accuracy_frags[w] = 0;
+               ra.accuracy_hit[w] = 0;
+               ra.accuracy_fired[w] = 0;
+               ra.accuracy_cnt_hit[w] = 0;
+               ra.accuracy_cnt_fired[w] = 0;
+       }
+}
+
 void accuracy_add(entity this, Weapon w, float fired, float hit)
 {
        if (IS_INDEPENDENT_PLAYER(this)) return;
        entity a = CS(this).accuracy;
+       entity ra = this.roundaccuracy;
        if (!a) return;
        if (!hit && !fired) return;
        if (w == WEP_Null) return;
        int wepid = w.m_id;
        wepid -= WEP_FIRST;
        int b = accuracy_byte(a.accuracy_hit[wepid], a.accuracy_fired[wepid]);
-       if (hit)    a.accuracy_hit  [wepid] += hit;
-       if (fired)  a.accuracy_fired[wepid] += fired;
+       if (hit) {
+               a.accuracy_hit[wepid] += hit;
+               ra.accuracy_hit[wepid] += hit;
+       }
+       if (fired) {
+               a.accuracy_fired[wepid] += fired;
+               ra.accuracy_fired[wepid] += fired;
+       }
 
     if (hit && STAT(HIT_TIME, a) != time) { // only run this once per frame
         a.accuracy_cnt_hit[wepid] += 1;
+               ra.accuracy_cnt_hit[wepid] += 1;
         STAT(HIT_TIME, a) = time;
     }
 
     if (fired && a.fired_time != time) { // only run this once per frame
         a.accuracy_cnt_fired[wepid] += 1;
+               ra.accuracy_cnt_fired[wepid] += 1;
         a.fired_time = time;
     }
 
-       if (b == accuracy_byte(a.accuracy_hit[wepid], a.accuracy_fired[wepid])) return; // no change
+       if (!g_duel && b == accuracy_byte(a.accuracy_hit[wepid], a.accuracy_fired[wepid])) return; // no change
        int sf = 1 << (wepid % 24);
        a.SendFlags |= sf;
-       FOREACH_CLIENT(IS_SPEC(it) && it.enemy == this, { CS(it).accuracy.SendFlags |= sf; });
+       
+       if(!g_duel)
+               FOREACH_CLIENT(IS_SPEC(it) && it.enemy == this, { CS(it).accuracy.SendFlags |= sf; });
 }
 
 bool accuracy_isgooddamage(entity attacker, entity targ)
index d5d9f97d9fc469783ae5ff49bb799e02ff2f2941..cf698d98c8a4657dd19e7f32737c847fbb89c31c 100644 (file)
@@ -24,6 +24,7 @@ REPLICATE_INIT(bool, cvar_cl_accuracy_data_share);
 REPLICATE_INIT(bool, cvar_cl_accuracy_data_receive);
 
 .entity accuracy;
+.entity roundaccuracy;
 .float accuracy_frags[REGISTRY_MAX(Weapons)];
 
 .float accuracy_hit[REGISTRY_MAX(Weapons)];
@@ -43,6 +44,7 @@ void accuracy_resend(entity e);
 
 // update accuracy stats
 void accuracy_add(entity e, Weapon w, float fired, float hit);
+void roundaccuracy_clear(entity this);
 
 // helper
 bool accuracy_isgooddamage(entity attacker, entity targ);
index a8385b686aa87f3b456c9b25bc81bcea467bd7a6..435443ab221c76d95ffec0a79e24267a874f9861 100644 (file)
@@ -5,6 +5,7 @@
 #include <common/effects/all.qh>
 #include <common/net_linked.qh>
 #include <common/state.qh>
+#include <common/scores.qh>
 #include <common/util.qh>
 #include <common/weapons/_all.qh>
 #include <common/wepent.qh>
@@ -341,8 +342,9 @@ void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector
 
        IL_CLEAR(g_railgunhit);
 
-       if(headshot)
-               Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_HEADSHOT);
+       if(headshot) {
+               Give_Medal(this, HEADSHOT);
+       }
 
        // calculate hits and fired shots for hitscan
        if(this.(weaponentity))
@@ -496,8 +498,9 @@ void fireBullet_antilag(entity this, .entity weaponentity, vector start, vector
                        Damage_DamageInfo(start, 0, 0, 0, max(1, force) * normalize(dir) * -damage_fraction, dtype, 0, this);
        }
 
-       if(headshot)
-               Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_HEADSHOT);
+       if(headshot) {
+               Give_Medal(this, HEADSHOT);
+       }
 
        if(lag)
                antilag_restore_all(this);
index 7cfade409001f56f76f79bb4c207fa0b32095251..c9fe1e66f2d6444760f4292d5d2a510e8792191d 100644 (file)
@@ -6,6 +6,7 @@
 #include <common/mapobjects/platforms.qh>
 #include <common/monsters/_mod.qh>
 #include <common/mutators/mutator/status_effects/_mod.qh>
+#include <common/ent_cs.qh>
 #include <common/net_linked.qh>
 #include <common/notifications/all.qh>
 #include <common/resources/sv_resources.qh>
@@ -427,7 +428,7 @@ bool weaponLocked(entity player)
 {
        if (time < game_starttime && !sv_ready_restart_after_countdown) return true;
        if (player.player_blocked) return true;
-       if (game_stopped) return true;
+       if (game_stopped || game_timeout) return true;
        if (STAT(FROZEN, player)) return true;
        if (MUTATOR_CALLHOOK(LockWeapon, player)) return true;
        return false;
@@ -536,6 +537,7 @@ void W_WeaponFrame(Player actor, .entity weaponentity)
                                this.m_weapon = newwep;
                                this.weaponname = newwep.mdl;
                                this.bulletcounter = 0;
+                               actor.activewepid = newwep.m_id; // z411
                                newwep.wr_setup(newwep, actor, weaponentity);
                                this.state = WS_RAISE;
 
index ad40a389543bcb5698d2abc2a0ddd1068e1f0557..3848659d18f196df683a45f7a5000103cfe31f2e 100644 (file)
@@ -101,6 +101,27 @@ void PingPLReport_Spawn()
 
 const float SPAWNFLAG_NO_WAYPOINTS_FOR_ITEMS = 1;
 
+void send_TotalShards(entity to) {
+       // for RJZ
+       // Send total number of picked up shards
+       if(!autocvar_rjz_count_shards) return;
+       if(!IS_REAL_CLIENT(to)) return;
+       
+       msg_entity = to;
+       WriteHeader(MSG_ONE, TE_CSQC_TOTALSHARDS);
+       WriteInt24_t(MSG_ONE, total_shards);
+}
+
+void send_TotalShardsAll() {
+       // for RJZ
+       // Send total number of picked up shards
+       if(!autocvar_rjz_count_shards) return;
+       
+       FOREACH_CLIENT(IS_REAL_CLIENT(it) && (IS_SPEC(it) || IS_OBSERVER(it)), {
+               send_TotalShards(it);
+       });
+}
+
 void SetDefaultAlpha()
 {
        if (!MUTATOR_CALLHOOK(SetDefaultAlpha))
@@ -318,12 +339,15 @@ void cvar_changes_init()
                BADCVAR("g_mapinfo_ignore_warnings");
                BADCVAR("g_maplist_ignore_sizes");
                BADCVAR("g_maplist_sizes_count_bots");
-
                // long
                BADCVAR("hostname");
+               BADCVAR("hostname_full");
                BADCVAR("g_maplist");
                BADCVAR("g_maplist_mostrecent");
                BADCVAR("sv_motd");
+               BADCVAR("sv_motd_permanent");
+               
+               BADPREFIX("g_teamnames_");
                BADCVAR("sv_termsofservice_url");
 
                v = cvar_string(k);
@@ -371,6 +395,9 @@ void cvar_changes_init()
                BADCVAR("g_forced_respawn");
                BADCVAR("g_freezetag_point_leadlimit");
                BADCVAR("g_freezetag_point_limit");
+               BADCVAR("g_freezetag_revive_respawn");
+               BADCVAR("g_freezetag_round_stop");
+               BADCVAR("g_freezetag_round_respawn");
                BADCVAR("g_glowtrails");
                BADCVAR("g_hats");
                BADCVAR("g_casings");
@@ -394,6 +421,12 @@ void cvar_changes_init()
                BADCVAR("g_tmayhem_point_leadlimit");
                BADCVAR("leadlimit_and_fraglimit");
                BADCVAR("leadlimit_override");
+               BADCVAR("g_mayhem_scoringmethod");
+               BADCVAR("g_mayhem_scoringmethod_damage_weight");
+               BADCVAR("g_mayhem_scoringmethod_frag_weight");
+               BADCVAR("g_tmayhem_scoringmethod");
+               BADCVAR("g_tmayhem_scoringmethod_damage_weight");
+               BADCVAR("g_tmayhem_scoringmethod_frag_weight");
                BADCVAR("pausable");
                BADCVAR("sv_announcer");
                BADCVAR("sv_autopause");
@@ -431,6 +464,8 @@ void cvar_changes_init()
                BADPREFIX("sv_timeout_");
                BADPREFIX("sv_vote_");
                BADPREFIX("timelimit_");
+               BADPREFIX("sv_chat_");
+               BADPREFIX("sv_jingle_");
                BADPRESUFFIX("g_", "_round_timelimit");
 
                // allowed changes to server admins (please sync this to server.cfg)
@@ -450,6 +485,9 @@ void cvar_changes_init()
                BADCVAR("gametype");
                BADCVAR("g_antilag");
                BADCVAR("g_balance_teams");
+               BADCVAR("g_balance_teams_queue");
+               BADCVAR("g_balance_teams_remove");
+               BADCVAR("g_balance_teams_remove_wait");
                BADCVAR("g_balance_teams_prevent_imbalance");
                BADCVAR("g_balance_teams_scorefactor");
                BADCVAR("g_ban_sync_trusted_servers");
@@ -542,6 +580,15 @@ void cvar_changes_init()
                BADCVAR("g_grappling_hook");
                BADCVAR("g_jetpack");
 
+               // temporary for testing
+               // TODO remove before 0.8.3 release
+               BADCVAR("g_ca_weaponarena");
+               BADCVAR("g_freezetag_weaponarena");
+               BADCVAR("g_lms_weaponarena");
+               BADCVAR("g_mayhem_weaponarena");
+               BADCVAR("g_tmayhem_weaponarena");
+               BADCVAR("g_ctf_stalemate_time");
+
 #undef BADPRESUFFIX
 #undef BADPREFIX
 #undef BADCVAR
@@ -1065,6 +1112,14 @@ spawnfunc(worldspawn)
 
        WinningConditionHelper(this); // set worldstatus
 
+       round_handler_Activate(!warmup_stage);
+       
+       // for RJZ
+       if (autocvar_rjz_count_shards && warmup_stage) {
+               total_shards = -2;
+               send_TotalShardsAll();
+       }
+       
        if (autocvar_sv_autopause && server_is_dedicated && !wantrestart)
                // INITPRIO_LAST is too soon: bots either didn't join yet or didn't leave yet, see: bot_fixcount()
                defer(this, 5, Pause_TryPause_Dedicated);
@@ -1348,6 +1403,8 @@ void NextLevel()
        */
 
        //pos = FindIntermission ();
+       
+       sound(NULL, CH_INFO, SND_ENDMATCH, VOL_BASE, ATTN_NONE);
 
        VoteReset(true);
 
@@ -1358,6 +1415,11 @@ void NextLevel()
        WeaponStats_Shutdown();
 
        Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_Null); // kill all centerprints now
+       
+       // send winner notification
+       if(teamplay) {
+               Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, APP_TEAM_NUM(WinningConditionHelper_winnerteam, ANNCE_TEAM_WINS));
+       }
 
        if(autocvar_sv_eventlog)
                GameLogEcho(":gameover");
@@ -1379,6 +1441,29 @@ void NextLevel()
        });
 
        target_music_kill();
+       
+       // z411
+       if(autocvar_sv_jingle_end) {
+               int jingles_len = 0;
+               string jingles[32];
+               jingles[0] = "";
+               
+               FOREACH_WORD(autocvar_sv_jingle_end_list, it,
+               {
+                       jingles[jingles_len] = it;
+                       jingles_len++;
+               });
+               
+               if(jingles_len) {
+                       int song_to_play = rint(random() * (jingles_len - 1));
+               
+                       FOREACH_CLIENT(IS_REAL_CLIENT(it),
+                       {
+                               stuffcmd(it, "cd stop\n");
+                               _sound(it, CH_INFO, strcat("jingle/", jingles[song_to_play], ".ogg"), VOL_BASE * autocvar_sv_jingle_end_volume, ATTEN_NORM);
+                       });
+               }
+       }
 
        if(autocvar_g_campaign)
                CampaignPreIntermission();
@@ -1428,6 +1513,12 @@ void InitiateOvertime() // ONLY call this if InitiateSuddenDeath returned true
        //add one more overtime by simply extending the timelimit
        cvar_set("timelimit", ftos(autocvar_timelimit + autocvar_timelimit_overtime));
        Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime * 60);
+       
+       sound(NULL, CH_INFO, SND_OVERTIME, VOL_BASE, ATTN_NONE);
+       if(checkrules_overtimesadded == 1) {
+               Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_OVERTIME);
+               overtime_starttime = time;
+       }
 }
 
 float GetWinningCode(float fraglimitreached, float equality)
@@ -1479,7 +1570,52 @@ void ClearWinners()
        FOREACH_CLIENT(IS_PLAYER(it) || INGAME(it), { it.winning = 0; });
 }
 
-int fragsleft_last;
+void AnnounceNewLeader()
+{
+       // Don't announce if in warmup or just started
+       if(warmup_stage || time - game_starttime < 1) return;
+
+       if(teamplay) {
+               if (WinningConditionHelper_equality)
+                       Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_TEAM_LEADS_TIED);
+               else
+                       FOREACH_CLIENT(IS_PLAYER(it), {
+                               if(it.team == WinningConditionHelper_winnerteam)
+                                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_ANNCE, ANNCE_TEAM_LEADS_TEAM);
+                               else
+                                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_ANNCE, ANNCE_TEAM_LEADS_ENEMY);
+                       });
+                       Send_Notification(NOTIF_ALL_SPEC, NULL, MSG_ANNCE, APP_TEAM_NUM(WinningConditionHelper_winnerteam, ANNCE_TEAM_LEADS));
+       } else {
+               if (WinningConditionHelper_equality)
+               {
+                       Send_Notification(NOTIF_ONE, WinningConditionHelper_equality_one, MSG_ANNCE, ANNCE_LEAD_TIED);
+                       Send_Notification(NOTIF_ONE, WinningConditionHelper_equality_two, MSG_ANNCE, ANNCE_LEAD_TIED);
+               }
+               else
+               {
+                       Send_Notification(NOTIF_ONE, WinningConditionHelper_winner, MSG_ANNCE, ANNCE_LEAD_GAINED);
+                       Send_Notification(NOTIF_ONE, WinningConditionHelper_second, MSG_ANNCE, ANNCE_LEAD_LOST);
+               }
+       }
+}
+
+void AnnounceScores(float tm)
+{
+       WinningConditionHelper(NULL);
+       if (Score_NewLeader()) {
+               AnnounceNewLeader();
+       } else {
+               FOREACH_CLIENT(IS_PLAYER(it), {
+                       if(it.team == tm)
+                               Send_Notification(NOTIF_ONE_ONLY, it, MSG_ANNCE, ANNCE_TEAM_SCORES_TEAM);
+                       else
+                               Send_Notification(NOTIF_ONE_ONLY, it, MSG_ANNCE, ANNCE_TEAM_SCORES_ENEMY);
+               });
+               Send_Notification(NOTIF_ALL_SPEC, NULL, MSG_ANNCE, APP_TEAM_NUM(tm, ANNCE_TEAM_SCORES));
+       }
+}
+
 float WinningCondition_Scores(float limit, float leadlimit)
 {
        // TODO make everything use THIS winning condition (except LMS)
@@ -1512,7 +1648,6 @@ float WinningCondition_Scores(float limit, float leadlimit)
 
        if(MUTATOR_CALLHOOK(Scores_CountFragsRemaining))
        {
-               float fragsleft;
                if (checkrules_suddendeathend && time >= checkrules_suddendeathend)
                {
                        fragsleft = 1;
@@ -1544,7 +1679,13 @@ float WinningCondition_Scores(float limit, float leadlimit)
                        fragsleft_last = fragsleft;
                }
        }
-
+       
+       // z411 - lead announcer
+       if(MUTATOR_CALLHOOK(Scores_AnnounceLeads)) {
+               if (Score_NewLeader())
+                       AnnounceNewLeader();
+       }
+       
        bool fraglimit_reached = (limit && WinningConditionHelper_topscore >= limit);
        bool leadlimit_reached = (leadlimit && WinningConditionHelper_topscore - WinningConditionHelper_secondscore >= leadlimit);
 
@@ -1660,6 +1801,9 @@ void CheckRules_World()
                        // again, but this shouldn't hurt
                return;
        }
+       
+       // z411 don't check rules if we're in a timeout
+       if (game_timeout) return;
 
        float timelimit = autocvar_timelimit * 60;
        float fraglimit = autocvar_fraglimit;
@@ -1697,6 +1841,9 @@ void CheckRules_World()
                                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_RACE_FINISHLAP);
                        else
                                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_FRAG);
+                       checkrules_overtimesadded = 1;
+                       sound(NULL, CH_INFO, SND_OVERTIME, VOL_BASE, ATTN_NONE);
+                       Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_OVERTIME);
                }
        }
        else
@@ -2130,6 +2277,8 @@ void readlevelcvars()
        serverflags &= ~SERVERFLAG_ALLOW_FULLBRIGHT;
        if(cvar("sv_allow_fullbright"))
                serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT;
+       if(cvar("sv_forbid_pickuptimer"))
+               serverflags |= SERVERFLAG_FORBID_PICKUPTIMER;
 
        serverflags &= ~SERVERFLAG_FORBID_PICKUPTIMER;
        if(cvar("sv_forbid_pickuptimer"))
@@ -2455,7 +2604,7 @@ void RunThink(entity this, float dt)
 bool autocvar_sv_freezenonclients;
 void Physics_Frame()
 {
-       if(autocvar_sv_freezenonclients)
+       if(autocvar_sv_freezenonclients || game_timeout)
                return;
 
        IL_EACH(g_moveables, true,
index a7301dc799b1fa96bc5a3102d95bc71faa3bd167..dd0b18134c96bd09602273a6dc819432467f4c40 100644 (file)
@@ -29,6 +29,13 @@ float autocvar_timelimit_overtime;
 int autocvar_timelimit_overtimes;
 float autocvar_timelimit_suddendeath;
 
+// z411
+bool autocvar_sv_jingle_end;
+string autocvar_sv_jingle_end_list;
+float autocvar_sv_jingle_end_volume;
+
+float fragsleft;
+int fragsleft_last;
 bool autocvar_sv_mapformat_is_quake3;
 bool autocvar_sv_mapformat_is_quake2;
 
@@ -166,6 +173,13 @@ void readlevelcvars();
 .vector dropped_origin;
 void droptofloor(entity this);
 
+/* z411 for RJZ */
+bool autocvar_rjz_count_shards = false;
+bool autocvar_rjz_ranks = false;
+int  total_shards = 0;
+void send_TotalShards(entity to);
+void send_TotalShardsAll();
+
 IntrusiveList g_moveables;
 STATIC_INIT(g_moveables) { g_moveables = IL_NEW(); }
 
index 063425b2615ccb2e2484a722fc1a749bd9b00bee..b2cbae2ca6444d5283202e8793416b3e5d6ddec1 100644 (file)
@@ -19,7 +19,8 @@ alias sv_hook_firstjoin
 alias sv_hook_lastleave
 
 // restart server if all players hit "ready"-button
-set sv_ready_restart_after_countdown 0 "reset players and map items after the countdown ended, instead of at the beginning of the countdown"
+// BaI mod changes this to 1
+set sv_ready_restart_after_countdown 1 "reset players and map items after the countdown ended, instead of at the beginning of the countdown"
 
 alias sv_hook_readyrestart
 
@@ -200,8 +201,9 @@ set g_shootfromfixedorigin "" "if set to a string like 0 y z, the gun is moved t
 set g_weapon_stay 0 "1: ghost weapons can be picked up but give no ammo, thrown guns have ammo 2: ghost weapons can be picked up and refill ammo to one pickup size, thrown guns have no ammo (to prevent infinite ammo abuse)"
 set g_weapon_throwable 1 "if set to 1, weapons can be dropped"
 set g_powerups -1 "if set to 0 no powerups will spawn, if 1 they will spawn in all game modes, -1 is game mode default"
-set g_powerups_drop 0 "allow dropping powerups (1 = timer continues, 2 = timer freezes until picked up)"
-set g_powerups_drop_ondeath 1 "players will drop their powerups on death (1 = timer continues, 2 = timer freezes until picked up)"
+// BaI mod changes this
+set g_powerups_drop 2 "allow dropping powerups (1 = timer continues, 2 = timer freezes until picked up)"
+set g_powerups_drop_ondeath 2 "players will drop their powerups on death (1 = timer continues, 2 = timer freezes until picked up)"
 set g_powerups_stack 0 "enables stacking of powerup timers when picking up a powerup you already have; otherwise timer is reset to the time granted by the item, if greater than the time you currently have"
 set g_powerups_strength 1 "allow strength powerups to spawn"
 set g_powerups_shield 1 "allow shield powerups to spawn"
@@ -268,7 +270,8 @@ set timelimit_suddendeath 5 "number of minutes suddendeath mode lasts after all
 
 // common team values
 
-set teamplay_mode 4 "default teamplay setting in team games. 1 = no friendly fire, self damage. 2 = friendly fire and self damage enabled. 3 = no friendly fire, but self damage enabled. 4 = obey the cvars g_mirrordamage*, g_friendlyfire* and g_teamdamage*"
+// BaI mod changes this
+set teamplay_mode 2 "default teamplay setting in team games. 1 = no friendly fire, self damage. 2 = friendly fire and self damage enabled. 3 = no friendly fire, but self damage enabled. 4 = obey the cvars g_mirrordamage*, g_friendlyfire* and g_teamdamage*"
 set g_mirrordamage 0.7              "for teamplay_mode 4: mirror damage factor"
 set g_mirrordamage_virtual 1        "for teamplay_mode 4: do not actually apply mirror damage, just show graphics effect for it"
 set g_mirrordamage_onlyweapons 0    "for teamplay_mode 4: only apply mirror damage if the attack was from a weapon"
@@ -280,6 +283,9 @@ set g_teamdamage_resetspeed 20      "for teamplay_mode 4: how fast player's team
 
 set g_balance_teams 1 "automatically balance out players entering instead of asking them for their preferred team"
 set g_balance_teams_prevent_imbalance 1 "prevent players from changing to larger teams"
+set g_balance_teams_queue 0 "queue players before joining"
+set g_balance_teams_remove 0 "remove excess players from teams"
+set g_balance_teams_remove_wait 10 "seconds to warn everyone before removing an excess player (0 = immediately)"
 set g_changeteam_banned 0 "not allowed to change team"
 
 set sv_teamnagger 1 "enable a nag message when the teams are unbalanced"