]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Mario/morphed_explosivesmodel
authorMario <mario@smbclan.net>
Wed, 22 Aug 2018 08:11:08 +0000 (18:11 +1000)
committerMario <mario@smbclan.net>
Wed, 22 Aug 2018 08:11:08 +0000 (18:11 +1000)
173 files changed:
.gitlab-ci.yml
.tx/merge-base
bal-wep-samual.cfg
bal-wep-xdf.cfg
bal-wep-xonotic.cfg
bal-wep-xpm.cfg
check-translations.sh
commands.cfg
common.de.po
common.de_CH.po
common.fr.po
common.he.po
common.pt_BR.po
effects-high.cfg
effects-low.cfg
effects-med.cfg
effects-normal.cfg
effects-omg.cfg
effects-ultimate.cfg
effects-ultra.cfg
gfx/hud/default/as_defend.tga [new file with mode: 0644]
gfx/hud/default/as_destroy.tga [new file with mode: 0644]
gfx/hud/luma/as_defend.tga [new file with mode: 0644]
gfx/hud/luma/as_destroy.tga [new file with mode: 0644]
gfx/hud/luma/ok_weapon_rail.tga
gfx/hud/luma/ok_weapon_shotgun.tga
gfx/hud/luma/ok_weapon_smg.tga
gfx/hud/luma/weaponhmg.tga
gfx/hud/luma/weaponrpc.tga
languages.txt
models/player/gak.iqm_0.txt
models/player/gakmasked.iqm_0.txt
models/player/ignismasked.iqm_0.txt
models/player/seraphinamasked.iqm_0.txt
notifications.cfg
physicsX07.cfg
qcsrc/client/autocvars.qh
qcsrc/client/commands/cl_cmd.qc
qcsrc/client/csqcmodel_hooks.qc
qcsrc/client/defs.qh
qcsrc/client/hud/hud.qc
qcsrc/client/hud/panel/ammo.qc
qcsrc/client/hud/panel/centerprint.qc
qcsrc/client/hud/panel/modicons.qc
qcsrc/client/hud/panel/powerups.qc
qcsrc/client/hud/panel/quickmenu.qc
qcsrc/client/hud/panel/radar.qc
qcsrc/client/hud/panel/scoreboard.qc
qcsrc/client/hud/panel/scoreboard.qh
qcsrc/client/hud/panel/weapons.qc
qcsrc/client/main.qc
qcsrc/client/main.qh
qcsrc/client/mapvoting.qc
qcsrc/client/mapvoting.qh
qcsrc/client/miscfunctions.qc
qcsrc/client/player_skeleton.qc
qcsrc/client/teamradar.qc
qcsrc/client/view.qc
qcsrc/client/weapons/projectile.qc
qcsrc/common/campaign_common.qh
qcsrc/common/campaign_file.qc
qcsrc/common/command/command.qh
qcsrc/common/command/generic.qc
qcsrc/common/command/generic.qh
qcsrc/common/command/rpn.qc
qcsrc/common/command/rpn.qh
qcsrc/common/debug.qh
qcsrc/common/effects/all.inc
qcsrc/common/gamemodes/gamemode/assault/assault.qc
qcsrc/common/gamemodes/gamemode/assault/assault.qh
qcsrc/common/gamemodes/gamemode/clanarena/clanarena.qc
qcsrc/common/gamemodes/gamemode/ctf/ctf.qc
qcsrc/common/gamemodes/gamemode/domination/domination.qc
qcsrc/common/gamemodes/gamemode/freezetag/freezetag.qc
qcsrc/common/gamemodes/gamemode/invasion/invasion.qc
qcsrc/common/gamemodes/gamemode/keepaway/keepaway.qc
qcsrc/common/gamemodes/gamemode/keepaway/keepaway.qh
qcsrc/common/gamemodes/gamemode/keyhunt/keyhunt.qc
qcsrc/common/gamemodes/gamemode/nexball/nexball.qc
qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc
qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qh
qcsrc/common/gamemodes/gamemode/race/race.qc
qcsrc/common/gamemodes/gamemode/tdm/tdm.qc
qcsrc/common/gamemodes/sv_rules.qh
qcsrc/common/items/item.qh
qcsrc/common/items/item/powerup.qh
qcsrc/common/mapobjects/models.qh
qcsrc/common/mapobjects/trigger/jumppads.qh
qcsrc/common/mutators/mutator/overkill/okrpc.qc
qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qc
qcsrc/common/mutators/mutator/vampirehook/sv_vampirehook.qc
qcsrc/common/mutators/mutator/waypoints/all.inc
qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc
qcsrc/common/mutators/mutator/waypoints/waypointsprites.qh
qcsrc/common/notifications/all.inc
qcsrc/common/physics/movetypes/movetypes.qc
qcsrc/common/physics/player.qc
qcsrc/common/physics/player.qh
qcsrc/common/playerstats.qc
qcsrc/common/playerstats.qh
qcsrc/common/sounds/sound.qh
qcsrc/common/state.qc
qcsrc/common/t_items.qc
qcsrc/common/t_items.qh
qcsrc/common/teams.qh
qcsrc/common/turrets/sv_turrets.qc
qcsrc/common/vehicles/cl_vehicles.qc
qcsrc/common/vehicles/sv_vehicles.qc
qcsrc/common/weapons/weapon/arc.qc
qcsrc/common/weapons/weapon/hagar.qc
qcsrc/common/weapons/weapon/shotgun.qc
qcsrc/lib/i18n.qh
qcsrc/lib/oo.qh
qcsrc/menu/command/menu_cmd.qc
qcsrc/menu/item/listbox.qc
qcsrc/menu/xonotic/campaign.qc
qcsrc/menu/xonotic/demolist.qc
qcsrc/menu/xonotic/dialog_settings_game_messages.qc
qcsrc/menu/xonotic/gametypelist.qc
qcsrc/menu/xonotic/hudskinlist.qc
qcsrc/menu/xonotic/maplist.qc
qcsrc/menu/xonotic/playerlist.qc
qcsrc/menu/xonotic/playlist.qc
qcsrc/menu/xonotic/screenshotlist.qc
qcsrc/menu/xonotic/skinlist.qc
qcsrc/menu/xonotic/soundlist.qc
qcsrc/menu/xonotic/statslist.qc
qcsrc/server/bot/api.qh
qcsrc/server/bot/default/aim.qc
qcsrc/server/bot/default/aim.qh
qcsrc/server/bot/default/bot.qc
qcsrc/server/bot/default/bot.qh
qcsrc/server/bot/default/havocbot/havocbot.qc
qcsrc/server/bot/default/havocbot/havocbot.qh
qcsrc/server/bot/default/havocbot/roles.qc
qcsrc/server/bot/default/navigation.qc
qcsrc/server/bot/default/navigation.qh
qcsrc/server/bot/default/waypoints.qc
qcsrc/server/bot/default/waypoints.qh
qcsrc/server/cheats.qc
qcsrc/server/client.qc
qcsrc/server/command/banning.qc
qcsrc/server/command/banning.qh
qcsrc/server/command/cmd.qc
qcsrc/server/command/common.qc
qcsrc/server/command/common.qh
qcsrc/server/command/radarmap.qc
qcsrc/server/command/radarmap.qh
qcsrc/server/command/sv_cmd.qc
qcsrc/server/command/vote.qc
qcsrc/server/command/vote.qh
qcsrc/server/compat/quake.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_damage.qh
qcsrc/server/g_world.qc
qcsrc/server/g_world.qh
qcsrc/server/ipban.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/miscfunctions.qh
qcsrc/server/mutators/events.qh
qcsrc/server/player.qc
qcsrc/server/player.qh
qcsrc/server/round_handler.qc
qcsrc/server/round_handler.qh
qcsrc/server/scores_rules.qc
qcsrc/server/teamplay.qc
qcsrc/server/teamplay.qh
qcsrc/server/weapons/selection.qc
qcsrc/server/weapons/tracing.qc
qcsrc/server/weapons/weaponsystem.qc
xonotic-client.cfg
xonotic-server.cfg

index 844e70c6ad615aa1b1d32b9cdcedf27b6b4cf924..905853d3fbc380d8aee7cd9aac79447952ca1360 100644 (file)
@@ -29,7 +29,7 @@ test_sv_game:
     - wget -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints
     - wget -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache
     - make
-    - EXPECT=242ab47092837a05ba09f041b32bddb1
+    - EXPECT=a0397fc196d6e249ecda448bcc47a5ab
     - HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
       | tee /dev/stderr
       | grep '^:'
index ca7140deb4f39043ced90c760624d498c0f1b2a1..d15698b68730a588bc9947b1ab0d36958f1fe1c1 100644 (file)
@@ -1 +1 @@
-Wed Jun 20 07:24:25 CEST 2018
+Mon Jul 23 07:24:17 CEST 2018
index 380d93ed47acc76f5aae18c560b77962a49ad531..1816f3f2e921ce4de93ceabcc2bad978861fcdd4 100644 (file)
@@ -322,7 +322,7 @@ set g_balance_crylink_primary_spread 0.08
 set g_balance_crylink_reload_ammo 0
 set g_balance_crylink_reload_time 2
 set g_balance_crylink_secondary 1
-set g_balance_crylink_secondary_ammo 2
+set g_balance_crylink_secondary_ammo 3
 set g_balance_crylink_secondary_animtime 0.2
 set g_balance_crylink_secondary_bouncedamagefactor 0.5
 set g_balance_crylink_secondary_bounces 0
index fcf68678d197f048f1b4bad1a270890eea1d7cd4..2e0e74aa3d7a993b7a97f1ac1b43f9ead3bbc797 100644 (file)
@@ -256,7 +256,7 @@ set g_balance_crylink_primary_spread 0.08
 set g_balance_crylink_reload_ammo 0
 set g_balance_crylink_reload_time 2
 set g_balance_crylink_secondary 1
-set g_balance_crylink_secondary_ammo 2
+set g_balance_crylink_secondary_ammo 3
 set g_balance_crylink_secondary_animtime 0.2
 set g_balance_crylink_secondary_bouncedamagefactor 0
 set g_balance_crylink_secondary_bounces 0
@@ -392,7 +392,7 @@ set g_balance_devastator_guiderate 0
 set g_balance_devastator_guideratedelay 999
 set g_balance_devastator_guidestop 1
 set g_balance_devastator_health 30
-set g_balance_devastator_lifetime 100
+set g_balance_devastator_lifetime 20
 set g_balance_devastator_radius 110
 set g_balance_devastator_refire 0.9
 set g_balance_devastator_reload_ammo 0
index e55e860773424fdad08857e6b3c121c3b686c407..5c6ace7abd7c6649f82b9998570e562154431a8e 100644 (file)
@@ -256,7 +256,7 @@ set g_balance_crylink_primary_spread 0.08
 set g_balance_crylink_reload_ammo 0
 set g_balance_crylink_reload_time 2
 set g_balance_crylink_secondary 1
-set g_balance_crylink_secondary_ammo 2
+set g_balance_crylink_secondary_ammo 3
 set g_balance_crylink_secondary_animtime 0.2
 set g_balance_crylink_secondary_bouncedamagefactor 0.5
 set g_balance_crylink_secondary_bounces 0
@@ -883,7 +883,7 @@ set g_balance_okmachinegun_primary_ammo 1
 set g_balance_okmachinegun_primary_damage 25
 set g_balance_okmachinegun_primary_force 5
 set g_balance_okmachinegun_primary_refire 0.1
-set g_balance_okmachinegun_primary_solidpenetration 13.1
+set g_balance_okmachinegun_primary_solidpenetration 63
 set g_balance_okmachinegun_primary_spread_add 0.012
 set g_balance_okmachinegun_primary_spread_max 0.05
 set g_balance_okmachinegun_primary_spread_min 0
index b16e787f5e5a95c029e1c679405b6b7d37d00a08..a5438d1b7c65a39ebe33f27da62dfb47e3c5e359 100644 (file)
@@ -256,7 +256,7 @@ set g_balance_crylink_primary_spread 0.08
 set g_balance_crylink_reload_ammo 0
 set g_balance_crylink_reload_time 2
 set g_balance_crylink_secondary 1
-set g_balance_crylink_secondary_ammo 2
+set g_balance_crylink_secondary_ammo 3
 set g_balance_crylink_secondary_animtime 0.2
 set g_balance_crylink_secondary_bouncedamagefactor 0.5
 set g_balance_crylink_secondary_bounces 0
index 5e2ad5a54a1e099e1c33e88261fe1bf45857db8d..6a55b5ef732f3dff77418a4c06ead7660a8b2a6b 100755 (executable)
@@ -101,11 +101,11 @@ if [ x"$mode" = x"txt" ]; then
                                if [ "$p" -lt 50 ]; then
                                        continue
                                fi
-                               item="$l $l \"$l\" 0%"
+                               item="$l \"$l\" \"$l\" 0%"
                        fi
                        printf "%s\n" "$item" | sed -e "s/[0-9][0-9]*%/$p%/"
                done
-       } | tr '"' '\t' | sort -k3 | tr '\t' '"'
+       } | LC_ALL=C sort -t '"' -k4,4
 fi
 
 if [ x"$mode" = x"po" ]; then
index b2edf84788332b7da31d681a318c19d6fd2e807d..3e5e78e0ef5d5581404ff021824f3bb741013776 100644 (file)
@@ -40,6 +40,7 @@ if_client    "alias" help "cl_cmd help; cmd help"
 // networked/server common commands
 alias cvar_changes         "qc_cmd_svcmd  cvar_changes         ${* ?}" // Prints a list of all changed server cvars
 alias cvar_purechanges     "qc_cmd_svcmd  cvar_purechanges     ${* ?}" // Prints a list of all changed gameplay cvars
+alias editmob              "qc_cmd_svcmd  editmob              ${* ?}" // Modifies a monster or all monsters
 alias info                 "qc_cmd_svcmd  info                 ${* ?}" // Request for unique server information set up by admin
 alias ladder               "qc_cmd_svcmd  ladder               ${* ?}" // Get information about top players if supported
 alias lsmaps               "qc_cmd_svcmd  lsmaps               ${* ?}" // List maps which can be used with the current game mode
@@ -55,16 +56,26 @@ alias who                  "qc_cmd_svcmd  who                  ${* ?}" // Displa
 
 // generic commands (across all programs)
 alias addtolist            "qc_cmd_svmenu addtolist            ${* ?}" // Add a string to a cvar
+alias bufstr_get           "qc_cmd_svmenu bufstr_get           ${* ?}" // Examine a string buffer object
+alias cvar_localchanges    "qc_cmd_svmenu cvar_localchanges    ${* ?}" // Print locally changed cvars
 alias dumpcommands         "qc_cmd_svmenu dumpcommands         ${* ?}" // Dump all commands on the program to *_cmd_dump.txt
-alias dumpnotifs           "qc_cmd_svcl   dumpnotifs           ${* ?}" // Dump all notifications into notifications_dump.txt
+alias dumpnotifs           "qc_cmd_svmenu dumpnotifs           ${* ?}" // Dump all notifications into notifications_dump.txt
+alias dumpitems            "qc_cmd_svmenu dumpitems            ${* ?}" // Dump all items to the console
+alias dumpturrets          "qc_cmd_svmenu dumpturrets          ${* ?}" // Dump all turrets into turrets_dump.txt
+alias dumpweapons          "qc_cmd_svmenu dumpweapons          ${* ?}" // Dump all weapons into weapons_dump.txt
+alias find                 "qc_cmd_svmenu find                 ${* ?}" // Search through entities for matching classname
+alias findat               "qc_cmd_svmenu findat               ${* ?}" // Search through entities for matching origin
 alias maplist              "qc_cmd_svmenu maplist              ${* ?}" // Automatic control of maplist
+alias mx                   "qc_cmd_svmenu mx                   ${* ?}" // Send a matrix command
 alias nextframe            "qc_cmd_svmenu nextframe            ${* ?}" // Execute the given command next frame of this VM
 alias qc_curl              "qc_cmd_svmenu qc_curl              ${* ?}" // Queries a URL
 alias removefromlist       "qc_cmd_svmenu removefromlist       ${* ?}" // Remove a string from a cvar
-alias restartnotifs        "qc_cmd_svcl   restartnotifs        ${* ?}" // Re-initialize all notifications
+alias restartnotifs        "qc_cmd_svmenu restartnotifs        ${* ?}" // Re-initialize all notifications
 alias rpn                  "qc_cmd_svmenu rpn                  ${* ?}" // RPN calculator
+alias runtest              "qc_cmd_svmenu runtest              ${* ?}" // Run unit tests
 //alias settemp            "qc_cmd_svmenu settemp              ${* ?}" // Temporarily set a value to a cvar which is restored later
 //alias settemp_restore    "qc_cmd_svmenu settemp_restore      ${* ?}" // Restore all cvars set by settemp command
+alias version              "qc_cmd_svmenu version              ${* ?}" // Print the current version
 
 // other aliases for common commands
 alias g_hitplots_add "qc_cmd_svmenu rpn /g_hitplots_individuals g_hitplots_individuals ${1 !} union def"
@@ -116,6 +127,7 @@ alias menu_loadmap_prepare "disconnect; wait; g_campaign 0; menu_cmd rpn /_menu_
 // ==========================================================
 // commented out commands are really only intended for internal use
 alias blurtest             "qc_cmd_cl     blurtest             ${* ?}" // Feature for testing blur postprocessing
+alias boxparticles         "qc_cmd_cl     boxparticles         ${* ?}" // Spawn particles manually
 alias create_scrshot_ent   "qc_cmd_cl     create_scrshot_ent   ${* ?}" // Create an entity at this location for automatic screenshots
 alias debugmodel           "qc_cmd_cl     debugmodel           ${* ?}" // Spawn a debug model manually
 //alias handlevote         "qc_cmd_cl     handlevote           ${* ?}" // System to handle selecting a vote or option
@@ -123,6 +135,8 @@ alias hud                  "qc_cmd_cl     hud                  ${* ?}" // Comman
 alias localprint           "qc_cmd_cl     localprint           ${* ?}" // Create your own centerprint sent to yourself
 //alias mv_download        "qc_cmd_cl     mv_download          ${* ?}" // Retrieve mapshot picture from the server
 alias sendcvar             "qc_cmd_cl     sendcvar             ${* ?}" // Send a cvar to the server (like weaponpriority)
+alias weapon_find          "qc_cmd_cl     weapon_find          ${* ?}" // Show spawn locations of a weapon
+
 alias exit                 "quit"
 
 // other aliases for local commands
@@ -147,17 +161,16 @@ seta cl_autoswitch 1 "automatically switch to newly picked up weapons if they ar
 // commented out commands are really only intended for internal use, or already have declaration in the engine
 alias autoswitch           "qc_cmd_cmd    autoswitch           ${* ?}" // Whether or not to switch automatically when getting a better weapon
 alias clientversion        "qc_cmd_cmd    clientversion        ${* ?}" // Release version of the game
-//alias mv_getpicture      "qc_cmd_cmd    mv_getpicture        ${* ?}" // Retrieve mapshot picture from the server
 alias join                 "qc_cmd_cmd    join                 ${* ?}" // Become a player in the game
+alias minigame             "qc_cmd_cmd    minigame             ${* ?}" // Start a minigame
+//alias mv_getpicture      "qc_cmd_cmd    mv_getpicture        ${* ?}" // Retrieve mapshot picture from the server
+alias physics              "qc_cmd_cmd    physics              ${* ?}" // Change physics set
 alias ready                "qc_cmd_cmd    ready                ${* ?}" // Qualify as ready to end warmup stage (or restart server if allowed)
-alias reportcvar           "qc_cmd_cmd    reportcvar           ${* ?}" // Old system for sending a client cvar to the server
 //alias say                "qc_cmd_cmd    say                  ${* ?}" // Print a message to chat to all players
 //alias say_team           "qc_cmd_cmd    say_team             ${* ?}" // Print a message to chat to all team mates
 alias selectteam           "qc_cmd_cmd    selectteam           ${* ?}" // Attempt to choose a team to join into
 alias selfstuff            "qc_cmd_cmd    selfstuff            ${* ?}" // Stuffcmd a command to your own client
 alias sentcvar             "qc_cmd_cmd    sentcvar             ${* ?}" // New system for sending a client cvar to the server
-alias editmob              "qc_cmd_cmd    editmob              ${* ?}" // Edit a monster's properties
-alias physics              "qc_cmd_cmd    physics              ${* ?}" // Change physics set
 alias spectate             "qc_cmd_cmd    spectate             ${* ?}" // Become an observer
 alias suggestmap           "qc_cmd_cmd    suggestmap           ${* ?}" // Suggest a map to the mapvote at match end
 //alias tell               "qc_cmd_cmd    tell                 ${* ?}" // Send a message directly to a player
@@ -194,6 +207,7 @@ alias mobbutcher "editmob butcher ${* ?}"
 alias adminmsg             "qc_cmd_sv     adminmsg             ${* ?}" // Send an admin message to a client directly
 alias allready             "qc_cmd_sv     allready             ${* ?}" // Restart the server and reset the players
 alias allspec              "qc_cmd_sv     allspec              ${* ?}" // Force all players to spectate
+alias animbench            "qc_cmd_sv     animbench            ${* ?}" // Benchmark model animation (LAGS)
 alias anticheat            "qc_cmd_sv     anticheat            ${* ?}" // Create an anticheat report for a client
 alias bbox                 "qc_cmd_sv     bbox                 ${* ?}" // Print detailed information about world size
 alias bot_cmd              "qc_cmd_sv     bot_cmd              ${* ?}" // Control and send commands to bots
@@ -204,7 +218,6 @@ alias defer_clear_all      "qc_cmd_sv     defer_clear_all      ${* ?}" // Clear
 alias delrec               "qc_cmd_sv     delrec               ${* ?}" // Delete race time record for a map
 alias effectindexdump      "qc_cmd_sv     effectindexdump      ${* ?}" // Dump list of effects from code and effectinfo.txt
 alias extendmatchtime      "qc_cmd_sv     extendmatchtime      ${* ?}" // Increase the timelimit value incrementally
-alias find                 "qc_cmd_sv     find                 ${* ?}" // Search through entities for matching classname
 alias gametype             "qc_cmd_sv     gametype             ${* ?}" // Simple command to change the active gametype
 alias gettaginfo           "qc_cmd_sv     gettaginfo           ${* ?}" // Get specific information about a weapon model
 alias gotomap              "qc_cmd_sv     gotomap              ${* ?}" // Simple command to switch to another map
index f248daf3c81d93d5dc60c1ff11f49083d0c378a0..2423e3782526671792bb23d8d4049a07e7971f1f 100644 (file)
@@ -3,7 +3,7 @@
 # This file is distributed under the same license as the PACKAGE package.
 #
 # Translators:
-# Wuzzy <almikes@aol.com>, 2016-2017
+# Wuzzy <almikes@aol.com>, 2016-2018
 # Brot Brot <noah.schluessel@gmail.com>, 2015
 # cvcxc <hans.andersen72@yahoo.com>, 2013
 # divVerent <divVerent@xonotic.org>, 2011,2013
@@ -24,7 +24,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-09-23 19:12+0000\n"
+"PO-Revision-Date: 2018-07-13 16:04+0000\n"
 "Last-Translator: Wuzzy <almikes@aol.com>\n"
 "Language-Team: German (http://www.transifex.com/team-xonotic/xonotic/"
 "language/de/)\n"
@@ -48,7 +48,7 @@ msgstr "^1Konnte nicht nach %s schreiben\n"
 
 #: qcsrc/client/hud/panel/chat.qc:82
 msgid "^3Player^7: This is the chat area."
-msgstr "^3Player^7: Dies ist der Chat-Bereich."
+msgstr "^3Spieler^7: Dies ist der Chat-Bereich."
 
 #: qcsrc/client/hud/panel/engineinfo.qc:69
 #, c-format
@@ -210,7 +210,7 @@ msgstr "^3Doppelklicke ^7ein Panel für Panel-spezifische Optionen."
 
 #: qcsrc/client/hud/panel/infomessages.qc:227
 msgid "^3CTRL ^7to disable collision testing, ^3SHIFT ^7and"
-msgstr "^3STRG^7, um Kollisionstests zu deaktivieren, ^3SHIFT ^7und"
+msgstr "^3CTRL^7, um Kollisionstests zu deaktivieren, ^3SHIFT ^7und"
 
 #: qcsrc/client/hud/panel/infomessages.qc:228
 msgid "^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments."
@@ -222,7 +222,7 @@ msgstr "Persönliche Bestzeit"
 
 #: qcsrc/client/hud/panel/modicons.qc:576
 msgid "Server best"
-msgstr "Server Bestzeit"
+msgstr "Server-Bestzeit"
 
 #: qcsrc/client/hud/panel/notify.qc:115 qcsrc/client/hud/panel/notify.qc:116
 #: qcsrc/client/hud/panel/score.qc:59
@@ -285,7 +285,7 @@ msgstr "freier Gegenstand %x^7 (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:804
 msgid "QMCMD^free item, icon"
-msgstr "freier Gegenstand, icon"
+msgstr "freier Gegenstand, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:805
 msgid "QMCMD^took item (l:%l^7)"
@@ -293,7 +293,7 @@ msgstr "Gegenstand genommen (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:805
 msgid "QMCMD^took item, icon"
-msgstr "Gegenstand genommen, icon"
+msgstr "Gegenstand genommen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:806
 msgid "QMCMD^negative"
@@ -309,7 +309,7 @@ msgstr "brauche Hilfe (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:808
 msgid "QMCMD^need help, icon"
-msgstr "brauche Hilfe, icon"
+msgstr "brauche Hilfe, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:809
 msgid "QMCMD^enemy seen (l:%y^7)"
@@ -317,7 +317,7 @@ msgstr "Gegner gesehen (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:809
 msgid "QMCMD^enemy seen, icon"
-msgstr "Gegner gesehen, icon"
+msgstr "Gegner gesehen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:810
 msgid "QMCMD^flag seen (l:%y^7)"
@@ -325,7 +325,7 @@ msgstr "Flagge gesehen (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:810
 msgid "QMCMD^flag seen, icon"
-msgstr "Flagge gesehen, icon"
+msgstr "Flagge gesehen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:811
 msgid "QMCMD^defending (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
@@ -333,7 +333,7 @@ msgstr "verteidigen (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:811
 msgid "QMCMD^defending, icon"
-msgstr "verteidigen, icon"
+msgstr "verteidigen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:812
 msgid "QMCMD^roaming (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
@@ -341,7 +341,7 @@ msgstr "wandernd (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:812
 msgid "QMCMD^roaming, icon"
-msgstr "wandernd, icon"
+msgstr "wandernd, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:813
 msgid "QMCMD^attacking (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
@@ -349,7 +349,7 @@ msgstr "angreifen (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:813
 msgid "QMCMD^attacking, icon"
-msgstr "angreifen, Iion"
+msgstr "angreifen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:814
 msgid "QMCMD^killed flagcarrier (l:%y^7)"
@@ -357,7 +357,7 @@ msgstr "Flaggenträger getötet (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:814
 msgid "QMCMD^killed flagcarrier, icon"
-msgstr "Flaggenträger getötet, icon"
+msgstr "Flaggenträger getötet, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:815
 #, c-format
@@ -366,11 +366,11 @@ msgstr "Flagge fallen gelassen (l:%d^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:815
 msgid "QMCMD^dropped flag, icon"
-msgstr "Flagge fallen gelassen, icon"
+msgstr "Flagge fallen gelassen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^drop weapon, icon"
-msgstr "Waffe wegwerfen, icon"
+msgstr "Waffe wegwerfen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
@@ -378,7 +378,7 @@ msgstr "Waffe fallen gelassen %w^7 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^drop flag/key, icon"
-msgstr "Flagge/Schlüssel fallen gelassen, icon"
+msgstr "Flagge/Schlüssel fallen gelassen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^dropped flag/key %w^7 (l:%l^7)"
@@ -694,7 +694,7 @@ msgstr "ticks"
 msgid ""
 "You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"
 msgstr ""
-"Du kannst die Tabelle mit dem ^2scoreboard_columns_set-Befehl ändern.\n"
+"Du kannst die Punktetafel mit dem ^2scoreboard_columns_set-Befehl ändern.\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:296
 msgid "^3|---------------------------------------------------------------|\n"
@@ -792,7 +792,7 @@ msgstr "^3capzeit^7                  Zeit des schnellsten Captures (CTF)\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:319
 msgid "^3fckills^7                  Number of flag carrier kills\n"
-msgstr "^3fckills^7                  Anzahl der getöteten Flaggen-Träger\n"
+msgstr "^3fckills^7                  Anzahl der getöteten Flaggenträger\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:320
 msgid "^3returns^7                  Number of flag returns\n"
@@ -950,7 +950,7 @@ msgstr "Platzierungen"
 #: qcsrc/client/hud/panel/scoreboard.qc:1519
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:43
 msgid "Scoreboard"
-msgstr "Tabelle"
+msgstr "Punktetafel"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1584
 #, c-format
@@ -1022,7 +1022,7 @@ msgstr "Du bist tot, warte ^3%s^7 bis zum Respawn"
 #: qcsrc/client/hud/panel/scoreboard.qc:1707
 #, c-format
 msgid "You are dead, press ^2%s^7 to respawn"
-msgstr "Du bist tot, drücke ^2%s^7 um neu zu spawnen"
+msgstr "Du bist tot, drücke ^2%s^7, um neu zu spawnen"
 
 #: qcsrc/client/hud/panel/vote.qc:24
 msgid "^1You must answer before entering hud configure mode\n"
@@ -1070,11 +1070,11 @@ msgstr "Keine Munition mehr"
 
 #: qcsrc/client/hud/panel/weapons.qc:534
 msgid "Don't have"
-msgstr "Nicht vorhanden"
+msgstr "Hast du nicht"
 
 #: qcsrc/client/hud/panel/weapons.qc:538
 msgid "Unavailable"
-msgstr "Nicht verfügbar"
+msgstr "Fehlend"
 
 #: qcsrc/client/main.qc:1014
 msgid " qu/s"
@@ -1384,11 +1384,11 @@ msgstr "Vielleicht klappt es beim nächsten Mal!"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1172
 msgid "Tubular! Press \"Next Level\" to continue!"
-msgstr "Großartig! Drücke „Nächter Level“ zum Fortfahren!"
+msgstr "Großartig! Drücke „Nächstes Level“ zum Fortfahren!"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1174
 msgid "Wicked! Press \"Next Level\" to continue!"
-msgstr "Wahnsinn! Klicke \"Nächstes Level\" um weiter zu spielen!"
+msgstr "Wahnsinn! Drücke „Nächstes Level“ zum Fortfahren!"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1177
 msgid "Press the space bar to change your currently selected tile"
@@ -1419,7 +1419,7 @@ msgstr "Speichern"
 #: qcsrc/common/minigames/minigame/pp.qc:438
 #: qcsrc/common/minigames/minigame/ttt.qc:319
 msgid "Draw"
-msgstr "Zeichnen"
+msgstr "Unentschieden"
 
 #: qcsrc/common/minigames/minigame/c4.qc:378
 #: qcsrc/common/minigames/minigame/nmm.qc:601
@@ -1521,7 +1521,7 @@ msgstr "Nächstes Spiel"
 #: qcsrc/common/minigames/minigame/ps.qc:478
 #, c-format
 msgid "Pieces left: %s"
-msgstr "Verbleibende Spielfiguren: %s"
+msgstr "Figuren: %s"
 
 #: qcsrc/common/minigames/minigame/ps.qc:488
 msgid "No more valid moves"
@@ -2626,7 +2626,7 @@ msgstr "^BGDu hast ^F1%s^BG%s fallengelassen"
 #: qcsrc/common/notifications/all.inc:698
 #, c-format
 msgid "^BGYou got the ^F1%s"
-msgstr "^BG^F1%s^K1 erhalten"
+msgstr "^F1%s^BG erhalten"
 
 #: qcsrc/common/notifications/all.inc:385
 #: qcsrc/common/notifications/all.inc:699
@@ -2734,12 +2734,12 @@ msgstr "^BGTeam ^TC^TT^BG hielt den Ball zu lange fest"
 #: qcsrc/common/notifications/all.inc:412
 #, c-format
 msgid "^BG%s^BG captured %s^BG control point"
-msgstr "^BG%s^BG hat den Kontrollpunkt von %s^BG erobert"
+msgstr "^BG%s^BG hat einen Kontrollpunkt erobert: %s^BG"
 
 #: qcsrc/common/notifications/all.inc:413
 #, c-format
 msgid "^TC^TT^BG team %s^BG control point has been destroyed by %s"
-msgstr "^TC^TT^BGDer Kontrollpunkt vom Team %s^BG wurde von %s zerstört"
+msgstr "^TC^TT^BGEin Kontrollpunkt vom Team %s^BG wurde von %s zerstört"
 
 #: qcsrc/common/notifications/all.inc:414
 msgid "^TC^TT^BG generator has been destroyed"
@@ -2759,7 +2759,7 @@ msgstr "^BG%s^K1 hat Unsichtbarkeit aufgesammelt"
 #: qcsrc/common/notifications/all.inc:418
 #, c-format
 msgid "^BG%s^K1 picked up Shield"
-msgstr "^BG%s^K1 hat das Schild aufgenommen"
+msgstr "^BG%s^K1 hat den Schild aufgenommen"
 
 #: qcsrc/common/notifications/all.inc:419
 #, c-format
@@ -3596,7 +3596,7 @@ msgstr "^K1Deine Medizin-Granate ist ein wenig defekt"
 
 #: qcsrc/common/notifications/all.inc:644
 msgid "^K1You are respawning for running out of ammo..."
-msgstr "^K1Du wirst wiederbelebt weil du keine Munition mehr hast …"
+msgstr "^K1Du wirst wiederbelebt, weil du keine Munition mehr hast …"
 
 #: qcsrc/common/notifications/all.inc:644
 msgid "^K1You were killed for running out of ammo..."
@@ -3913,12 +3913,12 @@ msgstr "^F2Aktive Waffe: ^F1%s"
 #: qcsrc/common/notifications/all.inc:733
 #, c-format
 msgid "^BGYou captured %s^BG control point"
-msgstr "^BGDu hast den Kontrollpunkt von %s^BG erobert"
+msgstr "^BGDu hast einen Kontrollpunkt erobert: %s^BG"
 
 #: qcsrc/common/notifications/all.inc:734
 #, c-format
 msgid "^TC^TT^BG team captured %s^BG control point"
-msgstr "Team ^TC^TT^BG hat %ss^BG Kontrollpunkt erobert"
+msgstr "Team ^TC^TT^BG hat einen Kontrollpunkt erobert: %s^BG"
 
 #: qcsrc/common/notifications/all.inc:735
 msgid "^BGThis control point currently cannot be captured"
@@ -4019,7 +4019,7 @@ msgstr "^F2Ein Schild umgibt dich"
 
 #: qcsrc/common/notifications/all.inc:754
 msgid "^F2Shield has worn off"
-msgstr "^F2Das Schild ist wieder verschwunden"
+msgstr "^F2Der Schild ist wieder verschwunden"
 
 #: qcsrc/common/notifications/all.inc:756
 msgid "^F2You are on speed"
@@ -5257,7 +5257,7 @@ msgstr "Schriftgröße:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qh:6
 msgid "Centerprint Panel"
-msgstr "Nachrichten-Panel"
+msgstr "Zentralanzeigen-Panel"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:15
 msgid "Chat entries:"
@@ -5355,7 +5355,7 @@ msgstr "Beim Zuschauen zeigen"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:18
 msgid "PNL^Enabled even playing in warmup"
-msgstr "Auch in der Aufwärmphase zeigen"
+msgstr "Auch in Aufwärmphase zeigen"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:29
 msgid "Reduced"
@@ -5363,7 +5363,7 @@ msgstr "Reduziert"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:32
 msgid "Text/icon ratio:"
-msgstr "Text/Icon-Verhältnis:"
+msgstr "Text-/Icon-Verhältnis:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:35
 msgid "Hide spawned items"
@@ -5407,7 +5407,7 @@ msgstr "Eintrags-Ausblendung:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_notification.qh:6
 msgid "Notification Panel"
-msgstr "Anzeige-Panel"
+msgstr "Nachrichten-Panel"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:15
 #: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:14
@@ -5421,11 +5421,11 @@ msgstr "Panel anzeigen"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:17
 msgid "Panel enabled even observing"
-msgstr "Panel auch beim Zuschauen anzeigen"
+msgstr "Auch beim Zuschauen zeigen"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:18
 msgid "Panel enabled only in Race/CTS"
-msgstr "Panel nur in Rennen und CTS-Rennen anzeigen"
+msgstr "Nur in Rennen und CTS-Rennen zeigen"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:24
 msgid "Status bar"
@@ -5536,7 +5536,7 @@ msgstr "Rundenzeit-Panel"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:16
 msgid "Panel enabled in teamgames"
-msgstr "Panel in Team-Spieltypen aktivieren"
+msgstr "Panel in Teamspielen aktivieren"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:23
 msgid "Radar:"
@@ -6317,13 +6317,11 @@ msgstr "Spielmechanik-Mutatoren:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:160
 msgid "Enable dodging"
-msgstr ""
-"Ausweichmodus: Es ist möglich rasch zur Seite zu springen (spezielle "
-"Bewegung)"
+msgstr "Ausweichmanöver aktivieren"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:167
 msgid "All players are almost invisible"
-msgstr "Tarnmodus: Alle Spieler sind fast unsichtbar"
+msgstr "Alle Spieler sind fast unsichtbar"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:174
 msgid "Only possible to inflict damage on your enemy while he's airborne"
@@ -6333,15 +6331,15 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:178
 msgid "Damage done to your enemy gets added to your own health"
 msgstr ""
-"Vampirmodus: Der Schaden, dem du anderen Spielern zufügst, wird deiner "
-"eigenen Lebensenergie hinzugefügt"
+"Der Schaden, dem du anderen Spielern zufügst, wird deiner eigenen "
+"Lebensenergie hinzugefügt"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:183
 msgid ""
 "Amount of health below which your player gets stunned because of blood loss"
 msgstr ""
-"Blutverlust: Aktiviere diesen Modus und stelle den Wert der Lebensenergie, "
-"bei der Spieler auf Grund von Blutverlust betäubt wirken, ein"
+"Aktiviere diesen Modus und stelle den Wert der Lebensenergie, bei der "
+"Spieler auf Grund von Blutverlust betäubt wirken, ein"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:192
 msgid "Make things fall to the ground slower, lower value means lower gravity"
@@ -6390,10 +6388,9 @@ msgid ""
 "Selecting a weapon arena will give all players that weapon at spawn as well "
 "as unlimited ammo, and disable all other weapon pickups."
 msgstr ""
-"Waffen-Arenen: Die Auswahl einer Waffen-Arena führt dazu, dass jeder Spieler "
-"mit der gewählten Waffe startet. Diese hat unendlich viel Munition, andere "
-"Waffen sind nicht vorhanden – Spezielle Waffen-Arenen: Spieler starten mit "
-"allen Waffen und unendlich viel Munition"
+"Die Auswahl einer Waffen-Arena führt dazu, dass jeder Spieler mit der "
+"gewählten Waffe startet. Diese hat unendlich viel Munition, andere Waffen "
+"sind nicht vorhanden."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:255
 msgid "Most weapons"
@@ -6617,7 +6614,7 @@ msgstr "Musikplayer"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:48
 msgid "Auto record demos"
-msgstr "Wiederholungen automatisch aufzeichnen"
+msgstr "Wiederholungen autom. aufzeichnen"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:57
 msgid "Timedemo"
@@ -6708,7 +6705,7 @@ msgstr "Alle entfernen"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:43
 msgid "Auto screenshot scoreboard"
-msgstr "Screenshot der Tabelle automatisch anfertigen"
+msgstr "Auto-Screenshot der Punktetafel"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:63
 msgid "Open in the viewer"
@@ -7419,7 +7416,7 @@ msgstr "Scharf"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:163
 msgid "Decals"
-msgstr "Einschusslöcher"
+msgstr "Dekore"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:164
 msgid "Enable decals (bullet holes and blood) (default: enabled)"
@@ -7717,7 +7714,7 @@ msgstr "Dezimalstellen im Respawn-Countdown anzeigen"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:57
 msgid "Show accuracy underneath scoreboard"
-msgstr "Trefferquote unter Tabelle anzeigen"
+msgstr "Trefferquote unter Punktetafel anzeigen"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:61
 msgid "Waypoints"
@@ -7824,7 +7821,7 @@ msgstr "Um den HUD-Editor zu starten, muss ein Spiel gestartet werden."
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:23
 msgid "Do you wish to start a local game to set up the HUD?"
-msgstr "Willst du ein lokales Spiel starten, um das HUD zu editieren?"
+msgstr "Willst du ein lokales Spiel starten, um das HUD zu bearbeiten?"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:24
 msgid "Frag Information"
@@ -7840,7 +7837,7 @@ msgstr "Amokläufe nur anzeigen, wenn sie Achievements sind"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:34
 msgid "Show spree information in centerprints"
-msgstr "Amoklauf-Informationen in Centerprints anzeigen"
+msgstr "Amoklauf-Infos in Zentralanzeige zeigen"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:38
 msgid "Show spree information in death messages"
@@ -7872,7 +7869,7 @@ msgstr "In separater Zeile anzeigen"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:58
 msgid "Add extra frag information to centerprint when available"
-msgstr "Zusätzliche Frag-Informationen in Centerprint anzeigen, wenn verfügbar"
+msgstr "Zusätzliche Frag-Infos in Zentralanzeige zeigen, wenn verfügbar"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:62
 msgid "Add frag location to death messages when available"
@@ -7914,7 +7911,7 @@ msgstr "Powerup-Nachrichten"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:89
 msgid "Weapon centerprint notifications"
-msgstr "Waffen-Centerprint-Nachrichten"
+msgstr "Waffen-Zentralanzeigen-Nachrichten"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:92
 msgid "Weapon info message notifications"
@@ -7995,7 +7992,7 @@ msgstr "Nur in Nicht-Teamspielen"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:60
 msgid "Body fading:"
-msgstr "Ausblenden von Leichen:"
+msgstr "Leichenausblendung:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:63
 msgid "Gibs:"
@@ -8290,7 +8287,7 @@ msgstr "Auto-Springen"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:99
 msgid "Jetpack on jump:"
-msgstr "Jetpack aktiveren durch Springen:"
+msgstr "Jetpack bei Sprung:"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:101
 msgid "JPJUMP^Disabled"
@@ -8395,7 +8392,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:48
 msgid "Server queries/s:"
-msgstr "Server Anfragen/Sekunde:"
+msgstr "Serveranfragen/s:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:52
 msgid "Downloads:"
@@ -8589,11 +8586,12 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:10
 msgid "While connected language changes will be applied only to the menu,"
 msgstr ""
-"Während du verbunden bist, werden Sprachänderungen nur auf das Menü angewandt"
+"Während du verbunden bist, werden Sprachänderungen nur auf das Menü "
+"angewandt;"
 
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:12
 msgid "full language changes will take effect starting from the next game"
-msgstr "Volle Sprachänderungen finden erst nach dem Neustart des Spiels statt"
+msgstr "volle Sprachänderungen finden erst nach dem Neustart des Spiels statt."
 
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:16
 msgid "Disconnect now"
@@ -8940,7 +8938,7 @@ msgstr "Einzelspieler"
 #: qcsrc/menu/xonotic/dialog_singleplayer.qh:7
 msgid "Play the singleplayer campaign or instant action matches against bots"
 msgstr ""
-"Spiele die Einzelspieler-Kampagne oder habe Instant-Action Spiele gegen Bots"
+"Spiele die Einzelspieler-Kampagne oder spiele ein Schnellspiel gegen Bots"
 
 #: qcsrc/menu/xonotic/dialog_singleplayer_winner.qh:7
 msgid "Winner"
@@ -9492,7 +9490,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/util.qc:780
 msgid "Use default"
-msgstr "Standard verwenden"
+msgstr "Standard"
 
 #: qcsrc/menu/xonotic/util.qc:800
 msgid "Team Color:"
index d5c87645f5f5fca211aba727c93dcf7eaa11a7e5..2c2c96b5dace8b9b653ec744dc4139c7baba613c 100644 (file)
@@ -3,7 +3,7 @@
 # This file is distributed under the same license as the PACKAGE package.
 #
 # Translators:
-# Wuzzy <almikes@aol.com>, 2016-2017
+# Wuzzy <almikes@aol.com>, 2016-2018
 # Brot Brot <noah.schluessel@gmail.com>, 2015
 # cvcxc <hans.andersen72@yahoo.com>, 2013
 # divVerent <divVerent@xonotic.org>, 2011,2013
@@ -24,7 +24,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-09-23 19:12+0000\n"
+"PO-Revision-Date: 2018-07-13 16:04+0000\n"
 "Last-Translator: Wuzzy <almikes@aol.com>\n"
 "Language-Team: German (http://www.transifex.com/team-xonotic/xonotic/"
 "language/de/)\n"
@@ -48,7 +48,7 @@ msgstr "^1Konnte nicht nach %s schreiben\n"
 
 #: qcsrc/client/hud/panel/chat.qc:82
 msgid "^3Player^7: This is the chat area."
-msgstr "^3Player^7: Dies ist der Chat-Bereich."
+msgstr "^3Spieler^7: Dies ist der Chat-Bereich."
 
 #: qcsrc/client/hud/panel/engineinfo.qc:69
 #, c-format
@@ -210,7 +210,7 @@ msgstr "^3Doppelklicke ^7ein Panel für Panel-spezifische Optionen."
 
 #: qcsrc/client/hud/panel/infomessages.qc:227
 msgid "^3CTRL ^7to disable collision testing, ^3SHIFT ^7and"
-msgstr "^3STRG^7, um Kollisionstests zu deaktivieren, ^3SHIFT ^7und"
+msgstr "^3CTRL^7, um Kollisionstests zu deaktivieren, ^3SHIFT ^7und"
 
 #: qcsrc/client/hud/panel/infomessages.qc:228
 msgid "^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments."
@@ -222,7 +222,7 @@ msgstr "Persönliche Bestzeit"
 
 #: qcsrc/client/hud/panel/modicons.qc:576
 msgid "Server best"
-msgstr "Server Bestzeit"
+msgstr "Server-Bestzeit"
 
 #: qcsrc/client/hud/panel/notify.qc:115 qcsrc/client/hud/panel/notify.qc:116
 #: qcsrc/client/hud/panel/score.qc:59
@@ -285,7 +285,7 @@ msgstr "freier Gegenstand %x^7 (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:804
 msgid "QMCMD^free item, icon"
-msgstr "freier Gegenstand, icon"
+msgstr "freier Gegenstand, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:805
 msgid "QMCMD^took item (l:%l^7)"
@@ -293,7 +293,7 @@ msgstr "Gegenstand genommen (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:805
 msgid "QMCMD^took item, icon"
-msgstr "Gegenstand genommen, icon"
+msgstr "Gegenstand genommen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:806
 msgid "QMCMD^negative"
@@ -309,7 +309,7 @@ msgstr "brauche Hilfe (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:808
 msgid "QMCMD^need help, icon"
-msgstr "brauche Hilfe, icon"
+msgstr "brauche Hilfe, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:809
 msgid "QMCMD^enemy seen (l:%y^7)"
@@ -317,7 +317,7 @@ msgstr "Gegner gesehen (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:809
 msgid "QMCMD^enemy seen, icon"
-msgstr "Gegner gesehen, icon"
+msgstr "Gegner gesehen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:810
 msgid "QMCMD^flag seen (l:%y^7)"
@@ -325,7 +325,7 @@ msgstr "Flagge gesehen (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:810
 msgid "QMCMD^flag seen, icon"
-msgstr "Flagge gesehen, icon"
+msgstr "Flagge gesehen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:811
 msgid "QMCMD^defending (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
@@ -333,7 +333,7 @@ msgstr "verteidigen (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:811
 msgid "QMCMD^defending, icon"
-msgstr "verteidigen, icon"
+msgstr "verteidigen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:812
 msgid "QMCMD^roaming (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
@@ -341,7 +341,7 @@ msgstr "wandernd (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:812
 msgid "QMCMD^roaming, icon"
-msgstr "wandernd, icon"
+msgstr "wandernd, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:813
 msgid "QMCMD^attacking (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
@@ -349,7 +349,7 @@ msgstr "angreifen (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:813
 msgid "QMCMD^attacking, icon"
-msgstr "angreifen, Iion"
+msgstr "angreifen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:814
 msgid "QMCMD^killed flagcarrier (l:%y^7)"
@@ -357,7 +357,7 @@ msgstr "Flaggenträger getötet (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:814
 msgid "QMCMD^killed flagcarrier, icon"
-msgstr "Flaggenträger getötet, icon"
+msgstr "Flaggenträger getötet, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:815
 #, c-format
@@ -366,11 +366,11 @@ msgstr "Flagge fallen gelassen (l:%d^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:815
 msgid "QMCMD^dropped flag, icon"
-msgstr "Flagge fallen gelassen, icon"
+msgstr "Flagge fallen gelassen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^drop weapon, icon"
-msgstr "Waffe wegwerfen, icon"
+msgstr "Waffe wegwerfen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
@@ -378,7 +378,7 @@ msgstr "Waffe fallen gelassen %w^7 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^drop flag/key, icon"
-msgstr "Flagge/Schlüssel fallen gelassen, icon"
+msgstr "Flagge/Schlüssel fallen gelassen, Icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^dropped flag/key %w^7 (l:%l^7)"
@@ -694,7 +694,7 @@ msgstr "ticks"
 msgid ""
 "You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"
 msgstr ""
-"Du kannst die Tabelle mit dem ^2scoreboard_columns_set-Befehl ändern.\n"
+"Du kannst die Punktetafel mit dem ^2scoreboard_columns_set-Befehl ändern.\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:296
 msgid "^3|---------------------------------------------------------------|\n"
@@ -792,7 +792,7 @@ msgstr "^3capzeit^7                  Zeit des schnellsten Captures (CTF)\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:319
 msgid "^3fckills^7                  Number of flag carrier kills\n"
-msgstr "^3fckills^7                  Anzahl der getöteten Flaggen-Träger\n"
+msgstr "^3fckills^7                  Anzahl der getöteten Flaggenträger\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:320
 msgid "^3returns^7                  Number of flag returns\n"
@@ -950,7 +950,7 @@ msgstr "Platzierungen"
 #: qcsrc/client/hud/panel/scoreboard.qc:1519
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:43
 msgid "Scoreboard"
-msgstr "Tabelle"
+msgstr "Punktetafel"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1584
 #, c-format
@@ -1022,7 +1022,7 @@ msgstr "Du bist tot, warte ^3%s^7 bis zum Respawn"
 #: qcsrc/client/hud/panel/scoreboard.qc:1707
 #, c-format
 msgid "You are dead, press ^2%s^7 to respawn"
-msgstr "Du bist tot, drücke ^2%s^7 um neu zu spawnen"
+msgstr "Du bist tot, drücke ^2%s^7, um neu zu spawnen"
 
 #: qcsrc/client/hud/panel/vote.qc:24
 msgid "^1You must answer before entering hud configure mode\n"
@@ -1070,11 +1070,11 @@ msgstr "Keine Munition mehr"
 
 #: qcsrc/client/hud/panel/weapons.qc:534
 msgid "Don't have"
-msgstr "Nicht vorhanden"
+msgstr "Hast du nicht"
 
 #: qcsrc/client/hud/panel/weapons.qc:538
 msgid "Unavailable"
-msgstr "Nicht verfügbar"
+msgstr "Fehlend"
 
 #: qcsrc/client/main.qc:1014
 msgid " qu/s"
@@ -1384,11 +1384,11 @@ msgstr "Vielleicht klappt es beim nächsten Mal!"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1172
 msgid "Tubular! Press \"Next Level\" to continue!"
-msgstr "Grossartig! Drücke „Nächter Level“ zum Fortfahren!"
+msgstr "Grossartig! Drücke „Nächstes Level“ zum Fortfahren!"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1174
 msgid "Wicked! Press \"Next Level\" to continue!"
-msgstr "Wahnsinn! Klicke \"Nächstes Level\" um weiter zu spielen!"
+msgstr "Wahnsinn! Drücke „Nächstes Level“ zum Fortfahren!"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1177
 msgid "Press the space bar to change your currently selected tile"
@@ -1419,7 +1419,7 @@ msgstr "Speichern"
 #: qcsrc/common/minigames/minigame/pp.qc:438
 #: qcsrc/common/minigames/minigame/ttt.qc:319
 msgid "Draw"
-msgstr "Zeichnen"
+msgstr "Unentschieden"
 
 #: qcsrc/common/minigames/minigame/c4.qc:378
 #: qcsrc/common/minigames/minigame/nmm.qc:601
@@ -1521,7 +1521,7 @@ msgstr "Nächstes Spiel"
 #: qcsrc/common/minigames/minigame/ps.qc:478
 #, c-format
 msgid "Pieces left: %s"
-msgstr "Verbleibende Spielfiguren: %s"
+msgstr "Figuren: %s"
 
 #: qcsrc/common/minigames/minigame/ps.qc:488
 msgid "No more valid moves"
@@ -2626,7 +2626,7 @@ msgstr "^BGDu hast ^F1%s^BG%s fallengelassen"
 #: qcsrc/common/notifications/all.inc:698
 #, c-format
 msgid "^BGYou got the ^F1%s"
-msgstr "^BG^F1%s^K1 erhalten"
+msgstr "^F1%s^BG erhalten"
 
 #: qcsrc/common/notifications/all.inc:385
 #: qcsrc/common/notifications/all.inc:699
@@ -2734,12 +2734,12 @@ msgstr "^BGTeam ^TC^TT^BG hielt den Ball zu lange fest"
 #: qcsrc/common/notifications/all.inc:412
 #, c-format
 msgid "^BG%s^BG captured %s^BG control point"
-msgstr "^BG%s^BG hat den Kontrollpunkt von %s^BG erobert"
+msgstr "^BG%s^BG hat einen Kontrollpunkt erobert: %s^BG"
 
 #: qcsrc/common/notifications/all.inc:413
 #, c-format
 msgid "^TC^TT^BG team %s^BG control point has been destroyed by %s"
-msgstr "^TC^TT^BGDer Kontrollpunkt vom Team %s^BG wurde von %s zerstört"
+msgstr "^TC^TT^BGEin Kontrollpunkt vom Team %s^BG wurde von %s zerstört"
 
 #: qcsrc/common/notifications/all.inc:414
 msgid "^TC^TT^BG generator has been destroyed"
@@ -2759,7 +2759,7 @@ msgstr "^BG%s^K1 hat Unsichtbarkeit aufgesammelt"
 #: qcsrc/common/notifications/all.inc:418
 #, c-format
 msgid "^BG%s^K1 picked up Shield"
-msgstr "^BG%s^K1 hat das Schild aufgenommen"
+msgstr "^BG%s^K1 hat den Schild aufgenommen"
 
 #: qcsrc/common/notifications/all.inc:419
 #, c-format
@@ -3597,7 +3597,7 @@ msgstr "^K1Deine Medizin-Granate ist ein wenig defekt"
 
 #: qcsrc/common/notifications/all.inc:644
 msgid "^K1You are respawning for running out of ammo..."
-msgstr "^K1Du wirst wiederbelebt weil du keine Munition mehr hast …"
+msgstr "^K1Du wirst wiederbelebt, weil du keine Munition mehr hast …"
 
 #: qcsrc/common/notifications/all.inc:644
 msgid "^K1You were killed for running out of ammo..."
@@ -3914,12 +3914,12 @@ msgstr "^F2Aktive Waffe: ^F1%s"
 #: qcsrc/common/notifications/all.inc:733
 #, c-format
 msgid "^BGYou captured %s^BG control point"
-msgstr "^BGDu hast den Kontrollpunkt von %s^BG erobert"
+msgstr "^BGDu hast einen Kontrollpunkt erobert: %s^BG"
 
 #: qcsrc/common/notifications/all.inc:734
 #, c-format
 msgid "^TC^TT^BG team captured %s^BG control point"
-msgstr "Team ^TC^TT^BG hat %ss^BG Kontrollpunkt erobert"
+msgstr "Team ^TC^TT^BG hat einen Kontrollpunkt erobert: %s^BG"
 
 #: qcsrc/common/notifications/all.inc:735
 msgid "^BGThis control point currently cannot be captured"
@@ -4020,7 +4020,7 @@ msgstr "^F2Ein Schild umgibt dich"
 
 #: qcsrc/common/notifications/all.inc:754
 msgid "^F2Shield has worn off"
-msgstr "^F2Das Schild ist wieder verschwunden"
+msgstr "^F2Der Schild ist wieder verschwunden"
 
 #: qcsrc/common/notifications/all.inc:756
 msgid "^F2You are on speed"
@@ -5258,7 +5258,7 @@ msgstr "Schriftgrösse:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qh:6
 msgid "Centerprint Panel"
-msgstr "Nachrichten-Panel"
+msgstr "Zentralanzeigen-Panel"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:15
 msgid "Chat entries:"
@@ -5356,7 +5356,7 @@ msgstr "Beim Zuschauen zeigen"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:18
 msgid "PNL^Enabled even playing in warmup"
-msgstr "Auch in der Aufwärmphase zeigen"
+msgstr "Auch in Aufwärmphase zeigen"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:29
 msgid "Reduced"
@@ -5364,7 +5364,7 @@ msgstr "Reduziert"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:32
 msgid "Text/icon ratio:"
-msgstr "Text/Icon-Verhältnis:"
+msgstr "Text-/Icon-Verhältnis:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:35
 msgid "Hide spawned items"
@@ -5408,7 +5408,7 @@ msgstr "Eintrags-Ausblendung:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_notification.qh:6
 msgid "Notification Panel"
-msgstr "Anzeige-Panel"
+msgstr "Nachrichten-Panel"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:15
 #: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:14
@@ -5422,11 +5422,11 @@ msgstr "Panel anzeigen"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:17
 msgid "Panel enabled even observing"
-msgstr "Panel auch beim Zuschauen anzeigen"
+msgstr "Auch beim Zuschauen zeigen"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:18
 msgid "Panel enabled only in Race/CTS"
-msgstr "Panel nur in Rennen und CTS-Rennen anzeigen"
+msgstr "Nur in Rennen und CTS-Rennen zeigen"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:24
 msgid "Status bar"
@@ -5537,7 +5537,7 @@ msgstr "Rundenzeit-Panel"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:16
 msgid "Panel enabled in teamgames"
-msgstr "Panel in Team-Spieltypen aktivieren"
+msgstr "Panel in Teamspielen aktivieren"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:23
 msgid "Radar:"
@@ -6318,13 +6318,11 @@ msgstr "Spielmechanik-Mutatoren:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:160
 msgid "Enable dodging"
-msgstr ""
-"Ausweichmodus: Es ist möglich rasch zur Seite zu springen (spezielle "
-"Bewegung)"
+msgstr "Ausweichmanöver aktivieren"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:167
 msgid "All players are almost invisible"
-msgstr "Tarnmodus: Alle Spieler sind fast unsichtbar"
+msgstr "Alle Spieler sind fast unsichtbar"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:174
 msgid "Only possible to inflict damage on your enemy while he's airborne"
@@ -6334,15 +6332,15 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:178
 msgid "Damage done to your enemy gets added to your own health"
 msgstr ""
-"Vampirmodus: Der Schaden, dem du anderen Spielern zufügst, wird deiner "
-"eigenen Lebensenergie hinzugefügt"
+"Der Schaden, dem du anderen Spielern zufügst, wird deiner eigenen "
+"Lebensenergie hinzugefügt"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:183
 msgid ""
 "Amount of health below which your player gets stunned because of blood loss"
 msgstr ""
-"Blutverlust: Aktiviere diesen Modus und stelle den Wert der Lebensenergie, "
-"bei der Spieler auf Grund von Blutverlust betäubt wirken, ein"
+"Aktiviere diesen Modus und stelle den Wert der Lebensenergie, bei der "
+"Spieler auf Grund von Blutverlust betäubt wirken, ein"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:192
 msgid "Make things fall to the ground slower, lower value means lower gravity"
@@ -6391,10 +6389,9 @@ msgid ""
 "Selecting a weapon arena will give all players that weapon at spawn as well "
 "as unlimited ammo, and disable all other weapon pickups."
 msgstr ""
-"Waffen-Arenen: Die Auswahl einer Waffen-Arena führt dazu, dass jeder Spieler "
-"mit der gewählten Waffe startet. Diese hat unendlich viel Munition, andere "
-"Waffen sind nicht vorhanden – Spezielle Waffen-Arenen: Spieler starten mit "
-"allen Waffen und unendlich viel Munition"
+"Die Auswahl einer Waffen-Arena führt dazu, dass jeder Spieler mit der "
+"gewählten Waffe startet. Diese hat unendlich viel Munition, andere Waffen "
+"sind nicht vorhanden."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:255
 msgid "Most weapons"
@@ -6618,7 +6615,7 @@ msgstr "Musikplayer"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:48
 msgid "Auto record demos"
-msgstr "Wiederholungen automatisch aufzeichnen"
+msgstr "Wiederholungen autom. aufzeichnen"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:57
 msgid "Timedemo"
@@ -6709,7 +6706,7 @@ msgstr "Alle entfernen"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:43
 msgid "Auto screenshot scoreboard"
-msgstr "Screenshot der Tabelle automatisch anfertigen"
+msgstr "Auto-Screenshot der Punktetafel"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:63
 msgid "Open in the viewer"
@@ -7420,7 +7417,7 @@ msgstr "Scharf"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:163
 msgid "Decals"
-msgstr "Einschusslöcher"
+msgstr "Dekore"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:164
 msgid "Enable decals (bullet holes and blood) (default: enabled)"
@@ -7718,7 +7715,7 @@ msgstr "Dezimalstellen im Respawn-Countdown anzeigen"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:57
 msgid "Show accuracy underneath scoreboard"
-msgstr "Trefferquote unter Tabelle anzeigen"
+msgstr "Trefferquote unter Punktetafel anzeigen"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:61
 msgid "Waypoints"
@@ -7825,7 +7822,7 @@ msgstr "Um den HUD-Editor zu starten, muss ein Spiel gestartet werden."
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:23
 msgid "Do you wish to start a local game to set up the HUD?"
-msgstr "Willst du ein lokales Spiel starten, um das HUD zu editieren?"
+msgstr "Willst du ein lokales Spiel starten, um das HUD zu bearbeiten?"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:24
 msgid "Frag Information"
@@ -7841,7 +7838,7 @@ msgstr "Amokläufe nur anzeigen, wenn sie Achievements sind"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:34
 msgid "Show spree information in centerprints"
-msgstr "Amoklauf-Informationen in Centerprints anzeigen"
+msgstr "Amoklauf-Infos in Zentralanzeige zeigen"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:38
 msgid "Show spree information in death messages"
@@ -7873,7 +7870,7 @@ msgstr "In separater Zeile anzeigen"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:58
 msgid "Add extra frag information to centerprint when available"
-msgstr "Zusätzliche Frag-Informationen in Centerprint anzeigen, wenn verfügbar"
+msgstr "Zusätzliche Frag-Infos in Zentralanzeige zeigen, wenn verfügbar"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:62
 msgid "Add frag location to death messages when available"
@@ -7915,7 +7912,7 @@ msgstr "Powerup-Nachrichten"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:89
 msgid "Weapon centerprint notifications"
-msgstr "Waffen-Centerprint-Nachrichten"
+msgstr "Waffen-Zentralanzeigen-Nachrichten"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:92
 msgid "Weapon info message notifications"
@@ -7996,7 +7993,7 @@ msgstr "Nur in Nicht-Teamspielen"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:60
 msgid "Body fading:"
-msgstr "Ausblenden von Leichen:"
+msgstr "Leichenausblendung:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:63
 msgid "Gibs:"
@@ -8291,7 +8288,7 @@ msgstr "Auto-Springen"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:99
 msgid "Jetpack on jump:"
-msgstr "Jetpack aktiveren durch Springen:"
+msgstr "Jetpack bei Sprung:"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:101
 msgid "JPJUMP^Disabled"
@@ -8396,7 +8393,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:48
 msgid "Server queries/s:"
-msgstr "Server Anfragen/Sekunde:"
+msgstr "Serveranfragen/s:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:52
 msgid "Downloads:"
@@ -8590,11 +8587,12 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:10
 msgid "While connected language changes will be applied only to the menu,"
 msgstr ""
-"Während du verbunden bist, werden Sprachänderungen nur auf das Menü angewandt"
+"Während du verbunden bist, werden Sprachänderungen nur auf das Menü "
+"angewandt;"
 
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:12
 msgid "full language changes will take effect starting from the next game"
-msgstr "Volle Sprachänderungen finden erst nach dem Neustart des Spiels statt"
+msgstr "volle Sprachänderungen finden erst nach dem Neustart des Spiels statt."
 
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:16
 msgid "Disconnect now"
@@ -8941,7 +8939,7 @@ msgstr "Einzelspieler"
 #: qcsrc/menu/xonotic/dialog_singleplayer.qh:7
 msgid "Play the singleplayer campaign or instant action matches against bots"
 msgstr ""
-"Spiele die Einzelspieler-Kampagne oder habe Instant-Action Spiele gegen Bots"
+"Spiele die Einzelspieler-Kampagne oder spiele ein Schnellspiel gegen Bots"
 
 #: qcsrc/menu/xonotic/dialog_singleplayer_winner.qh:7
 msgid "Winner"
@@ -9493,7 +9491,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/util.qc:780
 msgid "Use default"
-msgstr "Standard verwenden"
+msgstr "Standard"
 
 #: qcsrc/menu/xonotic/util.qc:800
 msgid "Team Color:"
index 84391e6114ea7ba0d9010dd5dee41ed46820185b..4a3b837d1c3bbf8cfff28783d13ac3688d437ee2 100644 (file)
 # RedGuff <domsau2@yahoo.fr>, 2014
 # Yannick Le Guen <leguen.yannick@gmail.com>, 2013
 # Hugo Locurcio, 2013
-# Yannick Le Guen <leguen.yannick@gmail.com>, 2013-2017
+# Yannick Le Guen <leguen.yannick@gmail.com>, 2013-2018
 msgid ""
 msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-09-14 13:32+0000\n"
+"PO-Revision-Date: 2018-07-08 09:28+0000\n"
 "Last-Translator: Yannick Le Guen <leguen.yannick@gmail.com>\n"
 "Language-Team: French (http://www.transifex.com/team-xonotic/xonotic/"
 "language/fr/)\n"
@@ -3086,12 +3086,12 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:484
 #, c-format
 msgid "^BG%s%s^K1 was sniped by ^BG%s^K1's Machine Gun%s%s"
-msgstr "^BG%s%s^K1 a été abattu par la Mitrailleuse de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 a été abattu par la Mitraillette de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:485
 #, c-format
 msgid "^BG%s%s^K1 was riddled full of holes by ^BG%s^K1's Machine Gun%s%s"
-msgstr "^BG%s%s^K1 a été criblé de balles par la Mitrailleuse de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 a été criblé de balles par la Mitraillette de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:486
 #: qcsrc/common/notifications/all.inc:790
@@ -4631,7 +4631,7 @@ msgstr "Grappin"
 
 #: qcsrc/common/weapons/weapon/machinegun.qc:17
 msgid "MachineGun"
-msgstr "Mitrailleuse"
+msgstr "Mitraillette"
 
 #: qcsrc/common/weapons/weapon/minelayer.qc:17
 msgid "Mine Layer"
index 593e684a646c9714c90d90cbf02bf197633a270b..f158cef5b8f5c2a755f0310dc7c1978e4836a448 100644 (file)
@@ -3,13 +3,14 @@
 # This file is distributed under the same license as the PACKAGE package.
 #
 # Translators:
+# nad le <nadavlevi726@gmail.com>, 2018
 msgid ""
 msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-05 15:06+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\n"
+"PO-Revision-Date: 2018-07-18 12:01+0000\n"
+"Last-Translator: nad le <nadavlevi726@gmail.com>\n"
 "Language-Team: Hebrew (http://www.transifex.com/team-xonotic/xonotic/"
 "language/he/)\n"
 "Language: he\n"
@@ -65,12 +66,12 @@ msgstr ""
 #: qcsrc/client/hud/panel/infomessages.qc:102
 #: qcsrc/client/hud/panel/infomessages.qc:106
 msgid "next weapon"
-msgstr ""
+msgstr "נשק הבא"
 
 #: qcsrc/client/hud/panel/infomessages.qc:102
 #: qcsrc/client/hud/panel/infomessages.qc:106
 msgid "previous weapon"
-msgstr ""
+msgstr "נשק קודם"
 
 #: qcsrc/client/hud/panel/infomessages.qc:106
 #, c-format
@@ -100,7 +101,7 @@ msgstr ""
 #: qcsrc/client/hud/panel/infomessages.qc:111
 #: qcsrc/menu/xonotic/keybinder.qc:94
 msgid "server info"
-msgstr ""
+msgstr "מידע על השרת"
 
 #: qcsrc/client/hud/panel/infomessages.qc:124
 msgid "^1Match has already begun"
@@ -140,7 +141,7 @@ msgstr ""
 #: qcsrc/client/hud/panel/infomessages.qc:175
 #: qcsrc/menu/xonotic/keybinder.qc:91
 msgid "ready"
-msgstr ""
+msgstr "מוכן"
 
 #: qcsrc/client/hud/panel/infomessages.qc:162
 #, c-format
@@ -172,7 +173,7 @@ msgstr ""
 #: qcsrc/client/hud/panel/infomessages.qc:199
 #: qcsrc/menu/xonotic/keybinder.qc:102
 msgid "team menu"
-msgstr ""
+msgstr "תפריט צוות"
 
 #: qcsrc/client/hud/panel/infomessages.qc:209
 msgid "^1Spectating this player:"
@@ -225,7 +226,7 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:636
 msgid "Continue..."
-msgstr ""
+msgstr "המשך..."
 
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
@@ -500,12 +501,12 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/racetimer.qc:61
 msgid "Start line"
-msgstr ""
+msgstr "קו התחלה"
 
 #: qcsrc/client/hud/panel/racetimer.qc:63
 #: qcsrc/client/hud/panel/racetimer.qc:67
 msgid "Finish line"
-msgstr ""
+msgstr "קו סיום"
 
 #: qcsrc/client/hud/panel/racetimer.qc:65
 #, c-format
@@ -1010,7 +1011,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:16
 #: qcsrc/menu/xonotic/dialog_uid2name.qc:15
 msgid "Yes"
-msgstr ""
+msgstr "כן"
 
 #: qcsrc/client/hud/panel/vote.qc:127 qcsrc/menu/xonotic/dialog_firstrun.qc:83
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:21
@@ -1020,7 +1021,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:17
 #: qcsrc/menu/xonotic/dialog_uid2name.qc:17
 msgid "No"
-msgstr ""
+msgstr "לא"
 
 #: qcsrc/client/hud/panel/weapons.qc:530
 msgid "Out of ammo"
@@ -1032,7 +1033,7 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/weapons.qc:538
 msgid "Unavailable"
-msgstr ""
+msgstr "לא זמין"
 
 #: qcsrc/client/main.qc:1014
 msgid " qu/s"
@@ -1078,7 +1079,7 @@ msgstr ""
 
 #: qcsrc/client/mapvoting.qc:365
 msgid "Vote for a map"
-msgstr ""
+msgstr "הצבע למפה"
 
 #: qcsrc/client/mapvoting.qc:382
 #, c-format
@@ -1181,11 +1182,11 @@ msgstr ""
 
 #: qcsrc/common/mapinfo.qh:126
 msgid "Race"
-msgstr ""
+msgstr "מרוץ"
 
 #: qcsrc/common/mapinfo.qh:126
 msgid "Race against other players to the finish line"
-msgstr ""
+msgstr "התחרה נגד שחקנים אחרים לקו הסיום"
 
 #: qcsrc/common/mapinfo.qh:160
 msgid "Race CTS"
@@ -1205,7 +1206,7 @@ msgstr ""
 
 #: qcsrc/common/mapinfo.qh:220
 msgid "Capture the Flag"
-msgstr ""
+msgstr "תפוס את הדגל"
 
 #: qcsrc/common/mapinfo.qh:220
 msgid ""
@@ -1308,7 +1309,7 @@ msgstr ""
 
 #: qcsrc/common/minigames/cl_minigames_hud.qc:403
 msgid "Exit Menu"
-msgstr ""
+msgstr "צא מהתפריט"
 
 #: qcsrc/common/minigames/cl_minigames_hud.qc:415
 #: qcsrc/menu/xonotic/dialog_multiplayer.qc:16
@@ -1317,7 +1318,7 @@ msgstr ""
 
 #: qcsrc/common/minigames/cl_minigames_hud.qc:418
 msgid "Join"
-msgstr ""
+msgstr "הצטרף"
 
 #: qcsrc/common/minigames/cl_minigames_hud.qc:489
 msgid "Minigames"
@@ -1345,7 +1346,7 @@ msgstr ""
 
 #: qcsrc/common/minigames/minigame/bd.qc:1404
 msgid "Next Level"
-msgstr ""
+msgstr "שלב הבא"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1405
 msgid "Restart"
@@ -1358,7 +1359,7 @@ msgstr ""
 #: qcsrc/common/minigames/minigame/bd.qc:1407
 #: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:37
 msgid "Save"
-msgstr ""
+msgstr "שמור"
 
 #: qcsrc/common/minigames/minigame/c4.qc:373
 #: qcsrc/common/minigames/minigame/pp.qc:438
@@ -1414,15 +1415,15 @@ msgstr ""
 
 #: qcsrc/common/minigames/minigame/pong.qc:651
 msgid "Start Match"
-msgstr ""
+msgstr "התחל משחק"
 
 #: qcsrc/common/minigames/minigame/pong.qc:652
 msgid "Add AI player"
-msgstr ""
+msgstr "הוסף שחקן מחשב"
 
 #: qcsrc/common/minigames/minigame/pong.qc:653
 msgid "Remove AI player"
-msgstr ""
+msgstr "הסר שחקן מחשב"
 
 #: qcsrc/common/minigames/minigame/pp.qc:443
 #: qcsrc/common/minigames/minigame/ttt.qc:324
@@ -1451,7 +1452,7 @@ msgstr ""
 #: qcsrc/common/minigames/minigame/pp.qc:582
 #: qcsrc/common/minigames/minigame/ttt.qc:665
 msgid "Next Match"
-msgstr ""
+msgstr "משחק הבא"
 
 #: qcsrc/common/minigames/minigame/ps.qc:478
 #, c-format
@@ -1464,7 +1465,7 @@ msgstr ""
 
 #: qcsrc/common/minigames/minigame/ps.qc:491
 msgid "Well done, you win!"
-msgstr ""
+msgstr "כל הכבוד, ניצחת!"
 
 #: qcsrc/common/minigames/minigame/ps.qc:494
 msgid "Jump a piece over another to capture it"
@@ -1477,7 +1478,7 @@ msgstr ""
 #: qcsrc/common/monsters/monster/mage.qh:17
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:18
 msgid "Mage"
-msgstr ""
+msgstr "קוסם"
 
 #: qcsrc/common/monsters/monster/mage.qh:29
 msgid "Mage spike"
@@ -1491,7 +1492,7 @@ msgstr ""
 #: qcsrc/common/monsters/monster/spider.qh:17
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:16
 msgid "Spider"
-msgstr ""
+msgstr "עכביש"
 
 #: qcsrc/common/monsters/monster/spider.qh:28
 msgid "Spider attack"
@@ -1509,11 +1510,11 @@ msgstr ""
 #: qcsrc/common/monsters/monster/zombie.qh:17
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:15
 msgid "Zombie"
-msgstr ""
+msgstr "זומבי"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:15
 msgid "Ammo"
-msgstr ""
+msgstr "תחמושת"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:24
 msgid "Resistance"
@@ -1522,7 +1523,7 @@ msgstr ""
 #: qcsrc/common/mutators/mutator/buffs/all.inc:33
 #: qcsrc/common/mutators/mutator/instagib/items.qh:94
 msgid "Speed"
-msgstr ""
+msgstr "מהירות"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:43
 msgid "Medic"
@@ -1610,7 +1611,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:109
 #: qcsrc/menu/xonotic/util.qc:775
 msgid "Color:"
-msgstr ""
+msgstr "צבע:"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:47
 msgid "Draw damage numbers for friendly fire"
@@ -1654,7 +1655,7 @@ msgstr ""
 
 #: qcsrc/common/mutators/mutator/nades/nades.qh:32
 msgid "Grenade"
-msgstr ""
+msgstr "רימון"
 
 #: qcsrc/common/mutators/mutator/overkill/hmg.qh:17
 msgid "Heavy Machine Gun"
@@ -1674,15 +1675,15 @@ msgstr ""
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:5
 msgid "Here"
-msgstr ""
+msgstr "כאן"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:6
 msgid "DANGER"
-msgstr ""
+msgstr "סכנה"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:8
 msgid "Frozen!"
-msgstr ""
+msgstr "קפוא!"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:10
 msgid "Item"
@@ -1776,12 +1777,12 @@ msgstr ""
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:39
 msgid "Run here"
-msgstr ""
+msgstr "רוץ לכאן"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:45
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:48
 msgid "Ball"
-msgstr ""
+msgstr "כדור"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:46
 msgid "Ball carrier"
@@ -1798,19 +1799,19 @@ msgstr ""
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:57
 msgid "Weapon"
-msgstr ""
+msgstr "נשק"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:59
 msgid "Monster"
-msgstr ""
+msgstr "מפלצת"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:61
 msgid "Vehicle"
-msgstr ""
+msgstr "רכב"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:62
 msgid "Intruder!"
-msgstr ""
+msgstr "פולש!"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:64
 msgid "Tagged"
@@ -4332,7 +4333,7 @@ msgstr ""
 
 #: qcsrc/common/turrets/turret/plasma_weapon.qh:7
 msgid "Plasma"
-msgstr ""
+msgstr "פלזמה"
 
 #: qcsrc/common/turrets/turret/tesla.qh:13
 #: qcsrc/common/turrets/turret/tesla_weapon.qh:7
@@ -4462,7 +4463,7 @@ msgstr ""
 
 #: qcsrc/common/weapons/weapon/shotgun.qc:17
 msgid "Shotgun"
-msgstr ""
+msgstr "שוטגן"
 
 #: qcsrc/common/weapons/weapon/tuba.qc:17
 #, no-c-format
@@ -4712,7 +4713,7 @@ msgstr ""
 
 #: qcsrc/menu/command/menu_cmd.qc:79
 msgid "Available options:\n"
-msgstr ""
+msgstr "אפשרויות זמינות:\n"
 
 #: qcsrc/menu/command/menu_cmd.qc:128
 msgid "Invalid command. For a list of supported commands, try menu_cmd help.\n"
@@ -4745,7 +4746,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/credits.qc:48
 msgid "Website"
-msgstr ""
+msgstr "אתר"
 
 #: qcsrc/menu/xonotic/credits.qc:53
 msgid "Stats"
@@ -4925,7 +4926,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/cvarlist.qc:93
 msgid "private"
-msgstr ""
+msgstr "פרטי"
 
 #: qcsrc/menu/xonotic/cvarlist.qc:95
 msgid "engine setting"
@@ -4946,7 +4947,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_credits.qh:7
 msgid "Credits"
-msgstr ""
+msgstr "קרדיטים"
 
 #: qcsrc/menu/xonotic/dialog_credits.qh:8
 msgid "The Xonotic credits"
@@ -4962,7 +4963,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:45
 #: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:28
 msgid "Name:"
-msgstr ""
+msgstr "שם:"
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:53
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:60
@@ -4983,11 +4984,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:88
 msgid "Save settings"
-msgstr ""
+msgstr "שמור הגדרות"
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qh:6
 msgid "Welcome"
-msgstr ""
+msgstr "ברוך הבא"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:16
 msgid "Ammunition display:"
@@ -5021,7 +5022,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:33
 #: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:18
 msgid "Left"
-msgstr ""
+msgstr "שמאל"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:32
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:32
@@ -5032,7 +5033,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:34
 #: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:20
 msgid "Right"
-msgstr ""
+msgstr "ימין"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qh:6
 msgid "Ammo Panel"
@@ -5059,7 +5060,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:19
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:71
 msgid "Center"
-msgstr ""
+msgstr "מרכז"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:35
 msgid "Font scale:"
@@ -5075,7 +5076,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:18
 msgid "Chat size:"
-msgstr ""
+msgstr "גודל צ'אט:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:22
 msgid "Chat lifetime:"
@@ -5265,15 +5266,15 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:37
 msgid "Speed:"
-msgstr ""
+msgstr "מהירות:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:38
 msgid "Include vertical speed"
-msgstr ""
+msgstr "כלול מהירות אנכית"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:49
 msgid "Speed unit:"
-msgstr ""
+msgstr "יחידת מידה למהירות:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:51
 msgid "qu/s"
@@ -5297,7 +5298,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:57
 msgid "Show"
-msgstr ""
+msgstr "הצג"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:60
 msgid "Top speed"
@@ -5419,7 +5420,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_score.qc:15
 msgid "Score:"
-msgstr ""
+msgstr "ניקוד:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_score.qc:18
 msgid "Rankings:"
@@ -5470,7 +5471,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:139
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:55
 msgid "Never"
-msgstr ""
+msgstr "לעולם לא"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:24
 #, c-format
@@ -5515,7 +5516,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:54
 msgid "Number"
-msgstr ""
+msgstr "מספר"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:55
 msgid "Bind"
@@ -5556,14 +5557,14 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:25
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:35
 msgid "Filter:"
-msgstr ""
+msgstr "מסנן:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:30
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:53
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:49
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:44
 msgid "Refresh"
-msgstr ""
+msgstr "רענן"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:33
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:30
@@ -5581,7 +5582,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:48
 #: qcsrc/menu/xonotic/util.qc:767
 msgid "Background:"
-msgstr ""
+msgstr "רקע:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:50
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:62
@@ -5662,7 +5663,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:13
 msgid "Monster:"
-msgstr ""
+msgstr "מפלצת:"
 
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:22
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:20
@@ -5672,7 +5673,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:23
 #: qcsrc/menu/xonotic/serverlist.qc:268
 msgid "Remove"
-msgstr ""
+msgstr "הסר"
 
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:25
 msgid "Move target:"
@@ -5696,7 +5697,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:31
 msgid "Colors:"
-msgstr ""
+msgstr "צבעים:"
 
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:33
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:39
@@ -5709,7 +5710,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer.qc:14
 msgid "Servers"
-msgstr ""
+msgstr "שרתים"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer.qc:15
 msgid "Find servers to play on"
@@ -5743,12 +5744,12 @@ msgstr ""
 #: qcsrc/menu/xonotic/util.qc:785 qcsrc/menu/xonotic/util.qc:794
 #: qcsrc/menu/xonotic/util.qc:802 qcsrc/menu/xonotic/util.qc:814
 msgid "Default"
-msgstr ""
+msgstr "ברירת מחדל"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:48
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:64
 msgid "Unlimited"
-msgstr ""
+msgstr "לא מוגבל"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:65
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:66
@@ -5789,7 +5790,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:70
 msgid "Lives:"
-msgstr ""
+msgstr "חיים:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:71
 msgid "Laps:"
@@ -5805,11 +5806,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:97
 msgid "Gametype"
-msgstr ""
+msgstr "סוג משחק"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:102
 msgid "Time limit:"
-msgstr ""
+msgstr "הגבלת זמן:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:104
 msgid "Timelimit in minutes that when hit, will end the match"
@@ -5827,7 +5828,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:107
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:159
 msgid "1 minute"
-msgstr ""
+msgstr "דקה אחת"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:124
 msgid "TIMLIM^Infinite"
@@ -5835,19 +5836,19 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:132
 msgid "Teams:"
-msgstr ""
+msgstr "צוותים:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:135
 msgid "2 teams"
-msgstr ""
+msgstr "2 צוותים"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:136
 msgid "3 teams"
-msgstr ""
+msgstr "3 צוותים"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:137
 msgid "4 teams"
-msgstr ""
+msgstr "4 צוותים"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:140
 msgid "Player slots:"
@@ -5881,15 +5882,15 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:153
 msgid "Beginner"
-msgstr ""
+msgstr "מתחיל"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:154
 msgid "You will win"
-msgstr ""
+msgstr "אתה תנצח"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:155
 msgid "You can win"
-msgstr ""
+msgstr "אתה יכול לנצח"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:156
 msgid "You might win"
@@ -5897,27 +5898,27 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:157
 msgid "Advanced"
-msgstr ""
+msgstr "מתקדם"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:158
 msgid "Expert"
-msgstr ""
+msgstr "מומחה"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:159
 msgid "Pro"
-msgstr ""
+msgstr "מקצוען"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:160
 msgid "Assassin"
-msgstr ""
+msgstr "מתנקש"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:161
 msgid "Unhuman"
-msgstr ""
+msgstr "לא אנושי"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:162
 msgid "Godlike"
-msgstr ""
+msgstr "דמוי אל"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:178
 msgid "Mutators..."
@@ -5955,7 +5956,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:217
 msgid "Add all"
-msgstr ""
+msgstr "הוסף הכל"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:218
 msgid "Add every available map to your selection"
@@ -5963,7 +5964,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:221
 msgid "Remove all"
-msgstr ""
+msgstr "הסר הכל"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:222
 msgid "Remove all the maps from your selection"
@@ -5975,20 +5976,20 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:58
 msgid "Title:"
-msgstr ""
+msgstr "כותרת:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:64
 msgid "Author:"
-msgstr ""
+msgstr "מחבר:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:70
 msgid "Game types:"
-msgstr ""
+msgstr "סוגי משחק:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:93
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:296
 msgid "Close"
-msgstr ""
+msgstr "סגור"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:96
 msgid "MAP^Play"
@@ -6044,7 +6045,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:75
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:282
 msgid "No start weapons"
-msgstr ""
+msgstr "ללא נשקי התחלה"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:77
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:195
@@ -6073,7 +6074,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:89
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:229
 msgid "Weapons stay"
-msgstr ""
+msgstr "נשקים נשארים"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:91
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:184
@@ -6129,7 +6130,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:178
 msgid "Damage done to your enemy gets added to your own health"
-msgstr ""
+msgstr "נזק שנעשה לאויב שלך מתווסף לחיים שלך"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:183
 msgid ""
@@ -6182,11 +6183,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:255
 msgid "Most weapons"
-msgstr ""
+msgstr "רוב הנשקים"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:260
 msgid "All weapons"
-msgstr ""
+msgstr "כל הנשקים"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:264
 msgid "Special arenas:"
@@ -6255,11 +6256,11 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:67
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:223
 msgid "Address:"
-msgstr ""
+msgstr "כתובת:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:78
 msgid "Info..."
-msgstr ""
+msgstr "מידע..."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:79
 msgid "Show more information about the currently highlighted server"
@@ -6268,7 +6269,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:84
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:303
 msgid "Join!"
-msgstr ""
+msgstr "הצטרף!"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:154
 #: qcsrc/menu/xonotic/serverlist.qc:1061
@@ -6282,7 +6283,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:161
 msgid "Official"
-msgstr ""
+msgstr "רשמי"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:169
 msgid "N/A (auth library missing, can't connect)"
@@ -6294,7 +6295,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:177
 msgid "Not supported (can't connect)"
-msgstr ""
+msgstr "לא נתמך(לא יכול להתחבר)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:179
 msgid "Not supported (won't encrypt)"
@@ -6330,11 +6331,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:231
 msgid "Gametype:"
-msgstr ""
+msgstr "סוג משחק:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:236
 msgid "Map:"
-msgstr ""
+msgstr "מפה:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:241
 msgid "Mod:"
@@ -6342,16 +6343,16 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:246
 msgid "Version:"
-msgstr ""
+msgstr "גרסה:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:251
 msgid "Settings:"
-msgstr ""
+msgstr "הגדרות:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:258
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:290
 msgid "Players:"
-msgstr ""
+msgstr "שחקנים:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:263
 msgid "Bots:"
@@ -6375,7 +6376,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qh:7
 msgid "Server Information"
-msgstr ""
+msgstr "מידע על השרת"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media.qc:25
 msgid "Demos"
@@ -6412,12 +6413,12 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:15
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc:15
 msgid "Do you really wish to disconnect now?"
-msgstr ""
+msgstr "אתה באמת רוצה להתנתק עכשיו?"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qh:6
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qh:6
 msgid "Disconnect"
-msgstr ""
+msgstr "התנתק"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc:13
 msgid "Timing a demo will disconnect you from the current match."
@@ -6445,7 +6446,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:55
 msgid "Random order"
-msgstr ""
+msgstr "סדר אקראי"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:60
 msgid "MUSICPL^Stop"
@@ -6485,19 +6486,19 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:139
 msgid "Reset"
-msgstr ""
+msgstr "אפס"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:144
 msgid "Previous"
-msgstr ""
+msgstr "קודם"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:147
 msgid "Next"
-msgstr ""
+msgstr "הבא"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:152
 msgid "Slide show"
-msgstr ""
+msgstr "מצגת שקופיות"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:34
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:21
@@ -6510,7 +6511,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:48
 msgid "Name"
-msgstr ""
+msgstr "שם"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:77
 msgid "Model"
@@ -6538,38 +6539,38 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:145
 msgid "Country"
-msgstr ""
+msgstr "מדינה"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:159
 msgid "Gender:"
-msgstr ""
+msgstr "מין:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:161
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:174
 msgid "Undisclosed"
-msgstr ""
+msgstr "לא ידוע"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:162
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:172
 msgid "Female"
-msgstr ""
+msgstr "נקבה"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:163
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:173
 msgid "Male"
-msgstr ""
+msgstr "זכר"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:166
 msgid "Gender"
-msgstr ""
+msgstr "מין"
 
 #: qcsrc/menu/xonotic/dialog_quit.qc:11
 msgid "Are you sure you want to quit?"
-msgstr ""
+msgstr "אתה בטוח שברצונך לצאת?"
 
 #: qcsrc/menu/xonotic/dialog_quit.qc:15
 msgid "Back to work..."
-msgstr ""
+msgstr "בחזרה לעבודה..."
 
 #: qcsrc/menu/xonotic/dialog_quit.qc:17
 msgid "I got some more fragging to do!"
@@ -6577,7 +6578,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_quit.qh:7
 msgid "Quit the game"
-msgstr ""
+msgstr "צא מהמשחק"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:15
 msgid "Model:"
@@ -6585,15 +6586,15 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:21
 msgid "Remove *"
-msgstr ""
+msgstr "הסר *"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:23
 msgid "Copy *"
-msgstr ""
+msgstr "העתק *"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:24
 msgid "Paste"
-msgstr ""
+msgstr "הדבק"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:26
 msgid "Bone:"
@@ -6693,7 +6694,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:81
 msgid "Show help"
-msgstr ""
+msgstr "הצג עזרה"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:82
 msgid "* is the object you are facing"
@@ -6709,23 +6710,23 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings.qc:19
 msgid "Effects"
-msgstr ""
+msgstr "אפקטים"
 
 #: qcsrc/menu/xonotic/dialog_settings.qc:20
 msgid "Audio"
-msgstr ""
+msgstr "שמע"
 
 #: qcsrc/menu/xonotic/dialog_settings.qc:22
 msgid "Game"
-msgstr ""
+msgstr "משחק"
 
 #: qcsrc/menu/xonotic/dialog_settings.qc:23
 msgid "Input"
-msgstr ""
+msgstr "קלט"
 
 #: qcsrc/menu/xonotic/dialog_settings.qc:24
 msgid "User"
-msgstr ""
+msgstr "משתמש"
 
 #: qcsrc/menu/xonotic/dialog_settings.qc:25
 #: qcsrc/menu/xonotic/keybinder.qc:105
@@ -6734,11 +6735,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings.qh:6
 msgid "Settings"
-msgstr ""
+msgstr "הגדרות"
 
 #: qcsrc/menu/xonotic/dialog_settings.qh:7
 msgid "Change the game settings"
-msgstr ""
+msgstr "שנה את הגדרות המשחק"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:29
 msgid "Master:"
@@ -6746,7 +6747,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:35
 msgid "Music:"
-msgstr ""
+msgstr "מוזיקה:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:43
 msgid "VOL^Ambient:"
@@ -6754,7 +6755,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:50
 msgid "Info:"
-msgstr ""
+msgstr "מידע:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:57
 msgid "Items:"
@@ -6766,7 +6767,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:71
 msgid "Player:"
-msgstr ""
+msgstr "שחקן:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:78
 msgid "Shots:"
@@ -6774,11 +6775,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:85
 msgid "Voice:"
-msgstr ""
+msgstr "קול:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:93
 msgid "Weapons:"
-msgstr ""
+msgstr "נשקים:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:99
 msgid "New style sound attenuation"
@@ -6842,7 +6843,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:123
 msgid "Stereo"
-msgstr ""
+msgstr "סטראו"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:124
 msgid "2.1"
@@ -6900,7 +6901,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:149
 msgid "Menu sounds"
-msgstr ""
+msgstr "צלילי תפריט"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:150
 msgid "Play sounds when clicking menu items"
@@ -6924,7 +6925,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:160
 msgid "5 minutes"
-msgstr ""
+msgstr "5 דקות"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:161
 msgid "WRN^Both"
@@ -6940,17 +6941,17 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:168
 msgid "Sometimes"
-msgstr ""
+msgstr "לפעמים"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:169
 msgid "Often"
-msgstr ""
+msgstr "לעתים קרובות"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:170
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:141
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:57
 msgid "Always"
-msgstr ""
+msgstr "תמיד"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:176
 msgid "Debug info about sounds"
@@ -7180,7 +7181,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:169
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:253
 msgid "Distance:"
-msgstr ""
+msgstr "מרחק"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:172
 msgid "Decals further away than this will not be drawn (default: 300)"
@@ -7188,7 +7189,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:176
 msgid "Time:"
-msgstr ""
+msgstr "זמן:"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:179
 msgid "Time in seconds before decals fade away (default: 2)"
@@ -7264,7 +7265,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:212
 msgid "Use normal maps"
-msgstr ""
+msgstr "השתמש במפות רגילות"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:213
 msgid "Enable use of directional shading on textures (default: enabled)"
@@ -7312,7 +7313,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:239
 msgid "Particles"
-msgstr ""
+msgstr "חלקיקים"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:240
 msgid "Spawnpoint effects"
@@ -7324,7 +7325,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:246
 msgid "Quality:"
-msgstr ""
+msgstr "איכות:"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:249
 msgid ""
@@ -7355,11 +7356,11 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:81
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:97
 msgid "Size:"
-msgstr ""
+msgstr "גודל:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:64
 msgid "By health"
-msgstr ""
+msgstr "לפי חיים"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:76
 msgid "Use rings to indicate weapon status"
@@ -7455,7 +7456,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:74
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:124
 msgid "Fontsize:"
-msgstr ""
+msgstr "גודל גופן:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:80
 msgid "Edge offset:"
@@ -7467,7 +7468,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:94
 msgid "Damage"
-msgstr ""
+msgstr "נזק"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:96
 msgid "Overlay:"
@@ -7487,11 +7488,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:114
 msgid "Show names above players"
-msgstr ""
+msgstr "הצג שמות מעל שחקנים"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:130
 msgid "Max distance:"
-msgstr ""
+msgstr "מרחק מקסימלי:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:136
 msgid "Decolorize:"
@@ -7597,7 +7598,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:65
 msgid "Gamemode Settings"
-msgstr ""
+msgstr "אפשרויות מצב משחק"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:67
 msgid "Display capture times in Capture The Flag"
@@ -7611,7 +7612,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:91
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:133
 msgid "Other"
-msgstr ""
+msgstr "אחר"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:78
 msgid "Display console messages in the top left corner"
@@ -7655,7 +7656,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qh:7
 msgid "Messages"
-msgstr ""
+msgstr "הודעות"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:30
 msgid "Items"
@@ -7696,7 +7697,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:49
 #: qcsrc/menu/xonotic/serverlist.qc:767
 msgid "Players"
-msgstr ""
+msgstr "שחקנים"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:51
 msgid "Force player models to mine"
@@ -7768,7 +7769,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:51
 msgid "3rd person perspective"
-msgstr ""
+msgstr "נקודת מבט מגוף שלישי"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:55
 msgid "Back distance"
@@ -7913,7 +7914,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qh:7
 #: qcsrc/menu/xonotic/keybinder.qc:43
 msgid "Weapons"
-msgstr ""
+msgstr "נשקים"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:33
 msgid "Key Bindings"
@@ -7925,23 +7926,23 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:41
 msgid "Edit..."
-msgstr ""
+msgstr "ערוך..."
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:47
 msgid "Clear"
-msgstr ""
+msgstr "נקה"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:52
 msgid "Reset all"
-msgstr ""
+msgstr "אפס הכל"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:57
 msgid "Mouse"
-msgstr ""
+msgstr "עכבר"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:59
 msgid "Sensitivity:"
-msgstr ""
+msgstr "רגישות:"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:61
 msgid "Mouse speed multiplier"
@@ -7991,7 +7992,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:96
 msgid "Automatically repeat jumping if holding jump"
-msgstr ""
+msgstr "המשך לקפוץ באופן אוטומטי אם מקש קפיצה לחוץ"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:99
 msgid "Jetpack on jump:"
@@ -8013,7 +8014,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:114
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:119
 msgid "Use joystick input"
-msgstr ""
+msgstr "התשתמש בקלט מג'ויסטיק"
 
 #: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:31
 msgid "Command when pressed:"
@@ -8025,7 +8026,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:40
 msgid "Cancel"
-msgstr ""
+msgstr "בטל"
 
 #: qcsrc/menu/xonotic/dialog_settings_input_userbind.qh:7
 msgid "User defined key bind"
@@ -8048,7 +8049,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:27
 msgid "Network"
-msgstr ""
+msgstr "רשת"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:29
 msgid "Client UDP port:"
@@ -8060,11 +8061,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:34
 msgid "Bandwidth:"
-msgstr ""
+msgstr "רוחב פס:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:36
 msgid "Specify your network speed"
-msgstr ""
+msgstr "צין את מהירות הרשת שלך"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:37
 msgid "56k"
@@ -8100,7 +8101,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:52
 msgid "Downloads:"
-msgstr ""
+msgstr "הורדות:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:54
 msgid "Maximum number of concurrent HTTP/FTP downloads"
@@ -8108,7 +8109,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:56
 msgid "Download speed:"
-msgstr ""
+msgstr "מהירות הורדה:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:69
 msgid "Local latency:"
@@ -8148,7 +8149,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:102
 msgid "Target:"
-msgstr ""
+msgstr "מטרה:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:104
 msgid "TRGT^Disabled"
@@ -8168,7 +8169,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:129
 msgid "Show frames per second"
-msgstr ""
+msgstr "הצג פריימים לשנייה"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:130
 msgid "Show your rendered frames per second"
@@ -8206,7 +8207,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:147
 msgid "Enable developer mode"
-msgstr ""
+msgstr "אפשר מצב מפתח"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:151
 msgid "Advanced settings..."
@@ -8235,23 +8236,23 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:49
 msgid "Type:"
-msgstr ""
+msgstr "סוג:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:53
 msgid "Value:"
-msgstr ""
+msgstr "ערך:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:70
 msgid "Description:"
-msgstr ""
+msgstr "תיאור:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qh:7
 msgid "Advanced settings"
-msgstr ""
+msgstr "אפשרויות מתקדמות"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:11
 msgid "Are you sure you want to reset all settings?"
-msgstr ""
+msgstr "האם אתה בטוח שברצונך לאפס את כל ההגדרות?"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:13
 msgid "This will create a backup config in your data directory"
@@ -8263,11 +8264,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:64
 msgid "Text Language"
-msgstr ""
+msgstr "שפת טקסט"
 
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:69
 msgid "Set language"
-msgstr ""
+msgstr "קבע שפה"
 
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:74
 msgid "Disable gore effects and harsh language"
@@ -8289,11 +8290,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:16
 msgid "Disconnect now"
-msgstr ""
+msgstr "התנתק עכשיו"
 
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:17
 msgid "Switch language"
-msgstr ""
+msgstr "החלף שפה"
 
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qh:6
 msgid "Warning"
@@ -8361,7 +8362,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:59
 msgid "Full screen"
-msgstr ""
+msgstr "מסך מלא"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:61
 msgid "Vertical Synchronization"
@@ -8481,7 +8482,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:119
 msgid "Brightness:"
-msgstr ""
+msgstr "בהירות:"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:121
 msgid "Brightness of black (default: 0)"
@@ -8489,7 +8490,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:123
 msgid "Contrast:"
-msgstr ""
+msgstr "ניגודיות:"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:125
 msgid "Brightness of white (default: 1)"
@@ -8611,7 +8612,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_singleplayer_winner.qh:7
 msgid "Winner"
-msgstr ""
+msgstr "מנצח"
 
 #: qcsrc/menu/xonotic/dialog_teamselect.qc:32
 msgid "join 'best' team (auto-select)"
@@ -8623,27 +8624,27 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_teamselect.qc:37
 msgid "red"
-msgstr ""
+msgstr "אדום"
 
 #: qcsrc/menu/xonotic/dialog_teamselect.qc:38
 msgid "blue"
-msgstr ""
+msgstr "כחול"
 
 #: qcsrc/menu/xonotic/dialog_teamselect.qc:39
 msgid "yellow"
-msgstr ""
+msgstr "צהוב"
 
 #: qcsrc/menu/xonotic/dialog_teamselect.qc:40
 msgid "pink"
-msgstr ""
+msgstr "ורוד"
 
 #: qcsrc/menu/xonotic/dialog_teamselect.qc:43
 msgid "spectate"
-msgstr ""
+msgstr "צפה"
 
 #: qcsrc/menu/xonotic/dialog_teamselect.qh:7
 msgid "Team Selection"
-msgstr ""
+msgstr "בחירת צוות"
 
 #: qcsrc/menu/xonotic/dialog_uid2name.qc:10
 msgid "Allow player statistics to use your nickname?"
@@ -8667,7 +8668,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/keybinder.qc:30
 msgid "forward"
-msgstr ""
+msgstr "קדימה"
 
 #: qcsrc/menu/xonotic/keybinder.qc:31
 msgid "backpedal"
@@ -8739,7 +8740,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/keybinder.qc:80
 msgid "screen shot"
-msgstr ""
+msgstr "צילום מסך"
 
 #: qcsrc/menu/xonotic/keybinder.qc:81
 msgid "maximize radar"
@@ -8771,11 +8772,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/keybinder.qc:89
 msgid "vote YES"
-msgstr ""
+msgstr "הצבע כן"
 
 #: qcsrc/menu/xonotic/keybinder.qc:90
 msgid "vote NO"
-msgstr ""
+msgstr "הצבע לא"
 
 #: qcsrc/menu/xonotic/keybinder.qc:93
 msgid "Client"
@@ -8787,11 +8788,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/keybinder.qc:96
 msgid "disconnect"
-msgstr ""
+msgstr "התנתק"
 
 #: qcsrc/menu/xonotic/keybinder.qc:97
 msgid "quit"
-msgstr ""
+msgstr "צא"
 
 #: qcsrc/menu/xonotic/keybinder.qc:101
 msgid "auto-join team"
@@ -8857,7 +8858,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/serverlist.qc:763
 msgid "Ping"
-msgstr ""
+msgstr "פינג"
 
 #: qcsrc/menu/xonotic/serverlist.qc:764
 msgid "Hostname"
@@ -8865,11 +8866,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/serverlist.qc:765
 msgid "Map"
-msgstr ""
+msgstr "מפה"
 
 #: qcsrc/menu/xonotic/serverlist.qc:766
 msgid "Type"
-msgstr ""
+msgstr "סוג"
 
 #: qcsrc/menu/xonotic/serverlist.qc:1060
 #, c-format
@@ -9005,10 +9006,13 @@ msgid ""
 "texture memory usage, but make the textures appear very blurry. (default: "
 "good)"
 msgstr ""
+"שנה את החדות של טקסטורות.\n"
+"הנמכה תגרום לצמצום יעיל של זיכרון שמשומש על ידי טקסטורות, אבל יגרום "
+"לטקסטורות להראות מאוד מטושטשות. (ברירת מחדל: טוב)"
 
 #: qcsrc/menu/xonotic/slider_resolution.qc:115
 msgid "Screen resolution"
-msgstr ""
+msgstr "רזולוציית מסך"
 
 #: qcsrc/menu/xonotic/slider_sbfadetime.qc:13
 msgid "PART^Slow"
@@ -9024,51 +9028,51 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/statslist.qc:29
 msgid "January"
-msgstr ""
+msgstr "ינואר"
 
 #: qcsrc/menu/xonotic/statslist.qc:30
 msgid "February"
-msgstr ""
+msgstr "פברואר"
 
 #: qcsrc/menu/xonotic/statslist.qc:31
 msgid "March"
-msgstr ""
+msgstr "מרץ"
 
 #: qcsrc/menu/xonotic/statslist.qc:32
 msgid "April"
-msgstr ""
+msgstr "אפריל"
 
 #: qcsrc/menu/xonotic/statslist.qc:33
 msgid "May"
-msgstr ""
+msgstr "מאי"
 
 #: qcsrc/menu/xonotic/statslist.qc:34
 msgid "June"
-msgstr ""
+msgstr "יוני"
 
 #: qcsrc/menu/xonotic/statslist.qc:35
 msgid "July"
-msgstr ""
+msgstr "יולי"
 
 #: qcsrc/menu/xonotic/statslist.qc:36
 msgid "August"
-msgstr ""
+msgstr "אוגוסט"
 
 #: qcsrc/menu/xonotic/statslist.qc:37
 msgid "September"
-msgstr ""
+msgstr "ספטמבר"
 
 #: qcsrc/menu/xonotic/statslist.qc:38
 msgid "October"
-msgstr ""
+msgstr "אוקטובר"
 
 #: qcsrc/menu/xonotic/statslist.qc:39
 msgid "November"
-msgstr ""
+msgstr "נובמבר"
 
 #: qcsrc/menu/xonotic/statslist.qc:40
 msgid "December"
-msgstr ""
+msgstr "דצמבר"
 
 #: qcsrc/menu/xonotic/statslist.qc:96
 msgid "Joined:"
@@ -9076,7 +9080,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/statslist.qc:103
 msgid "Last_Seen:"
-msgstr ""
+msgstr "נראה_לאחרונה:"
 
 #: qcsrc/menu/xonotic/statslist.qc:110
 msgid "Time_Played:"
@@ -9145,7 +9149,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/util.qc:780
 msgid "Use default"
-msgstr ""
+msgstr "השתמש בברירת מחדל"
 
 #: qcsrc/menu/xonotic/util.qc:800
 msgid "Team Color:"
index c3b8efc999459771b73f37b4db9e59c5e44f3117..7306a0dca6201651fca866d10660c7a7ae5b03c9 100644 (file)
@@ -14,7 +14,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2018-05-22 14:42+0000\n"
+"PO-Revision-Date: 2018-07-22 18:03+0000\n"
 "Last-Translator: Jean Trindade Pereira <jean_trindade2@hotmail.com>\n"
 "Language-Team: Portuguese (Brazil) (http://www.transifex.com/team-xonotic/"
 "xonotic/language/pt_BR/)\n"
@@ -27,7 +27,7 @@ msgstr ""
 #: qcsrc/client/hud/hud_config.qc:239
 #, c-format
 msgid "^2Successfully exported to %s! (Note: It's saved in data/data/)\n"
-msgstr "^2Exportado com sucesso para %s! (Nota: Foi salvo em data/data/)\n"
+msgstr "^2Exportado com sucesso para %s! (Nota: foi salvo em data/data/)\n"
 
 #: qcsrc/client/hud/hud_config.qc:243
 #, c-format
@@ -155,12 +155,11 @@ msgstr "%sAperte ^3%s%s assim que estiver pronto"
 #: qcsrc/client/hud/panel/infomessages.qc:167
 msgid "^2Waiting for others to ready up to end warmup..."
 msgstr ""
-"^2Esperando que os outros jogadores estejam prontos para acabar o "
-"aquecimento..."
+"^2Aguardando outros jogadores ficarem prontos para terminar o aquecimento..."
 
 #: qcsrc/client/hud/panel/infomessages.qc:169
 msgid "^2Waiting for others to ready up..."
-msgstr "^2Esperando que os outros jogadores estejam prontos..."
+msgstr "^2Aguardando outros jogadores ficarem prontos..."
 
 #: qcsrc/client/hud/panel/infomessages.qc:175
 #, c-format
@@ -183,7 +182,7 @@ msgstr "menu de equipe"
 
 #: qcsrc/client/hud/panel/infomessages.qc:209
 msgid "^1Spectating this player:"
-msgstr "^1Também estão assistindo a este jogador:"
+msgstr "^1Assistindo a este jogador:"
 
 #: qcsrc/client/hud/panel/infomessages.qc:209
 msgid "^1Spectating you:"
@@ -191,7 +190,7 @@ msgstr "^1Assistindo você:"
 
 #: qcsrc/client/hud/panel/infomessages.qc:225
 msgid "^7Press ^3ESC ^7to show HUD options."
-msgstr "^7Aperte ^3ESC ^7para exibir as opções de HUD."
+msgstr "^7Aperte ^3ESC ^7para exibir as opções de interface."
 
 #: qcsrc/client/hud/panel/infomessages.qc:226
 msgid "^3Doubleclick ^7a panel for panel-specific options."
@@ -201,7 +200,7 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/infomessages.qc:227
 msgid "^3CTRL ^7to disable collision testing, ^3SHIFT ^7and"
-msgstr "^3CTRL ^7para desligar teste de colisão, ^3SHIFT ^7e"
+msgstr "Use ^3CTRL ^7para desligar o teste de colisão, e ^3SHIFT ^7e"
 
 #: qcsrc/client/hud/panel/infomessages.qc:228
 msgid "^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments."
@@ -365,7 +364,7 @@ msgstr "Largar arma, ícone"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
-msgstr "Arma solta %w^7 (l:%l^7)"
+msgstr "Arma largada %w^7 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^drop flag/key, icon"
@@ -377,7 +376,7 @@ msgstr "Bandeira/Chave largada %w^7 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:821
 msgid "QMCMD^Send private message to"
-msgstr "Mandar mensagem privada para"
+msgstr "Enviar mensagem privada para"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:823
 #: qcsrc/client/hud/panel/quickmenu.qc:860
@@ -387,7 +386,7 @@ msgstr "Configurações"
 #: qcsrc/client/hud/panel/quickmenu.qc:824
 #: qcsrc/client/hud/panel/quickmenu.qc:831
 msgid "QMCMD^View/HUD settings"
-msgstr "Configurações de Exibição/HUD"
+msgstr "Configurações de exibição/interface"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:825
 msgid "QMCMD^3rd person view"
@@ -454,7 +453,7 @@ msgstr "Aumentar velocidade"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:851
 msgid "QMCMD^Decrease speed"
-msgstr "Diminuir velocidade"
+msgstr "Reduzir velocidade"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:852
 msgid "QMCMD^Wall collision off"
@@ -685,7 +684,7 @@ msgstr "ticks"
 msgid ""
 "You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"
 msgstr ""
-"Você pode modificar o placar usando o comando ^2scoreboard_columns_set.\n"
+"É possível modificar o placar usando o comando ^2scoreboard_columns_set.\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:296
 msgid "^3|---------------------------------------------------------------|\n"
@@ -701,13 +700,13 @@ msgstr "^2scoreboard_columns_set padrão\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:299
 msgid "^2scoreboard_columns_set ^7field1 field2 ...\n"
-msgstr "^2scoreboard_columns_set ^7campo1 campo2...\n"
+msgstr "^2scoreboard_columns_set ^7field1 field2...\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:300
 msgid "The following field names are recognized (case insensitive):\n"
 msgstr ""
-"Os seguintes nomes de campos são reconhecidos (maiúsculas/minúsculas não são "
-"distintas):\n"
+"Os seguintes nomes de campo são reconhecidos (maiúsculas e minúsculas não "
+"diferem):\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:301
 msgid "You can use a ^3|^7 to start the right-aligned fields.\n"
@@ -731,7 +730,7 @@ msgstr "^3elo^7 ELO do jogador\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:308
 msgid "^3kills^7                    Number of kills\n"
-msgstr "^3vítimas^7 Número de aniquilações\n"
+msgstr "^3vítimas^7 Número de vítimas\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:309
 msgid "^3deaths^7                   Number of deaths\n"
@@ -783,8 +782,7 @@ msgstr "^3tempodecaptura^7 Tempo da captura mais rápida (CTF)\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:319
 msgid "^3fckills^7                  Number of flag carrier kills\n"
-msgstr ""
-"^3pbndvítimas^7 Número de portadores de bandeiras mortos pelo jogador\n"
+msgstr "^3pbndvítimas^7 Número de portadores de bandeiras aniquilados\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:320
 msgid "^3returns^7                  Number of flag returns\n"
@@ -792,7 +790,7 @@ msgstr "^3retornos^7 Número de bandeiras retomadas\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:321
 msgid "^3drops^7                    Number of flag drops\n"
-msgstr "^3quedas^7 Número de bandeiras que foram soltas\n"
+msgstr "^3quedas^7 Número de bandeiras largadas\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:322
 msgid "^3lives^7                    Number of lives (LMS)\n"
@@ -804,18 +802,18 @@ msgstr "^3posição^7 Classificação do jogador\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:324
 msgid "^3pushes^7                   Number of players pushed into void\n"
-msgstr "^3empurrões^7 Número de jogadores empurrados para fora do mapa\n"
+msgstr "^3empurrões^7 Número de jogadores empurrados para o vazio\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:325
 msgid ""
 "^3destroyed^7                Number of keys destroyed by pushing them into "
 "void\n"
 msgstr ""
-"^3destruídas^7 Número de chaves destruídas ao empurrá-las para fora do mapa\n"
+"^3destruídas^7 Número de chaves destruídas ao empurrá-las para o vazio\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:326
 msgid "^3kckills^7                  Number of keys carrier kills\n"
-msgstr "^3pcvítimas^7 Número de portadores de chaves mortos pelo jogador\n"
+msgstr "^3pcvítimas^7 Número de portadores de chaves aniquilados\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:327
 msgid "^3losses^7                   Number of times a key was lost\n"
@@ -827,7 +825,7 @@ msgstr "^3voltas^7 Número de voltas concluídas (corrida/cts)\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:329
 msgid "^3time^7                     Total time raced (race/cts)\n"
-msgstr "^3tempo^7 Tempo total de corrida (corrida/cts)\n"
+msgstr "^3tempo^7 Tempo total em corridas (corrida/cts)\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:330
 msgid "^3fastest^7                  Time of fastest lap (race/cts)\n"
@@ -843,7 +841,7 @@ msgstr "^3tomados^7 Número de pontos de dominação tomados (DOM)\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:333
 msgid "^3bckills^7                  Number of ball carrier kills\n"
-msgstr "^3pblvítimas^7 Número de portadores de bolas mortos pelo jogador\n"
+msgstr "^3pblvítimas^7 Número de portadores de bolas aniquilados\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:334
 msgid ""
@@ -1017,7 +1015,8 @@ msgstr "Você morreu. Aperte ^2%s^7 para ressurgir"
 #: qcsrc/client/hud/panel/vote.qc:24
 msgid "^1You must answer before entering hud configure mode\n"
 msgstr ""
-"^1Você tem que responder antes de entrar no modo de configuração do HUD\n"
+"^1Você tem que responder antes de entrar no modo de configuração da "
+"interface\n"
 
 #: qcsrc/client/hud/panel/vote.qc:29
 msgid "^2Name ^7instead of \"^1Anonymous player^7\" in stats"
@@ -1033,7 +1032,7 @@ msgstr "Permitir que servidores armazenem e mostrem o seu nome?"
 
 #: qcsrc/client/hud/panel/vote.qc:121
 msgid "^1Configure the HUD"
-msgstr "^1Configurar o HUD"
+msgstr "^1Configurar a interface"
 
 #: qcsrc/client/hud/panel/vote.qc:125 qcsrc/menu/xonotic/dialog_firstrun.qc:82
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:18
@@ -5716,7 +5715,7 @@ msgstr "Painel das Armas"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:19
 msgid "HUD skins"
-msgstr "Visuais de HUD"
+msgstr "Visuais de interface"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:22
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:196
@@ -5783,7 +5782,7 @@ msgstr "Preenchimento:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:93
 msgid "HUD Dock:"
-msgstr "Camada do HUD:"
+msgstr "Camada da interface:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:95
 msgid "DOCK^Disabled"
@@ -5827,7 +5826,7 @@ msgstr "Sair da configuração"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qh:6
 msgid "Panel HUD Setup"
-msgstr "Painel de Configuração do HUD"
+msgstr "Painel de configuração da interface"
 
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:13
 msgid "Monster:"
@@ -7754,32 +7753,33 @@ msgstr "Sobreposição do dano:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:160
 msgid "Dynamic HUD"
-msgstr "HUD dinâmico"
+msgstr "Interface dinâmica"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:161
 msgid "HUD moves around following player's movement"
-msgstr "O HUD se move de acordo com o movimento do jogador"
+msgstr "A interface se move de acordo com o movimento do jogador"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:163
 msgid "Shake the HUD when hurt"
-msgstr "Vibrar o HUD ao ser atingido"
+msgstr "Vibrar a interface ao receber dano"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:167
 #: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qh:6
 msgid "Enter HUD editor"
-msgstr "Entrar no editor do HUD"
+msgstr "Entrar no editor de interface"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qh:7
 msgid "HUD"
-msgstr "HUD"
+msgstr "Interface"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:21
 msgid "In order for the HUD editor to show, you must first be in game."
-msgstr "Para o editor do HUD aparecer, é necessário estar jogando em um mapa."
+msgstr ""
+"Para abrir o editor de interface, é necessário estar jogando em um mapa."
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:23
 msgid "Do you wish to start a local game to set up the HUD?"
-msgstr "Quer iniciar um jogo local para personalizar o HUD?"
+msgstr "Quer iniciar um jogo local para personalizar a interface?"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:24
 msgid "Frag Information"
@@ -7888,7 +7888,7 @@ msgstr "Sons da contagem de ressurgimento"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:101
 msgid "Killstreak sounds"
-msgstr "Sons de sequências de mortes"
+msgstr "Sons de sequência de mortes"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:104
 msgid "Achievement sounds"
index 48c8253a3a2146538f1a9dfa6cc388f76b616ba4..597bb4660a9f0e063e6009652c8c0997dbbbd99e 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 1
 cl_playerdetailreduction 4
 gl_flashblend 0
 gl_picmip -1
+gl_texturecompression_2d 0
+gl_texturecompression_sky 0
 mod_q3bsp_nolightmaps 0
 r_bloom 1
 r_coronas 1
index b7e9a98a3a7a78fa396023d1f3fe615cd4cb4c4a..c9549581bddb35ebfc0fa858b347760aed609b13 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 0
 cl_playerdetailreduction 4
 gl_flashblend 1
 gl_picmip 1
+gl_texturecompression_2d 1
+gl_texturecompression_sky 1
 mod_q3bsp_nolightmaps 1
 r_bloom 0
 r_coronas 1
index 66eed5aa5d55dc897c6cd748848cd5ed82cb3efe..4ea20a1699d110c6742eab52260963c581b9ee66 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 0
 cl_playerdetailreduction 4
 gl_flashblend 0
 gl_picmip 0
+gl_texturecompression_2d 0
+gl_texturecompression_sky 1
 mod_q3bsp_nolightmaps 0
 r_bloom 0
 r_coronas 1
index 63dcd134a066f0c4255c4ad380f085249e177d0a..c421e5b325b6925c89b17e2a926fe018e5a170b2 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 1
 cl_playerdetailreduction 4
 gl_flashblend 0
 gl_picmip 0
+gl_texturecompression_2d 0
+gl_texturecompression_sky 1
 mod_q3bsp_nolightmaps 0
 r_bloom 0
 r_coronas 1
index 9018ee2c94375ba8740fa35f3357f55ff1d3cf15..7614417ce2027e42c4d711fce396faaaf7c1cd14 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 0
 cl_playerdetailreduction 4
 gl_flashblend 1
 gl_picmip 1337
+gl_texturecompression_2d 1
+gl_texturecompression_sky 1
 mod_q3bsp_nolightmaps 1
 r_bloom 0
 r_coronas 1
index 0cf3a899cbcebf5fa385a66ffd3fc07f326ca3c0..3ce6f55a7f01483f9a6c94d1c4a9d53405abbe8b 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 1
 cl_playerdetailreduction 0
 gl_flashblend 0
 gl_picmip -1
+gl_texturecompression_2d 0
+gl_texturecompression_sky 0
 mod_q3bsp_nolightmaps 0
 r_bloom 1
 r_coronas 1
index 5909f3b83dc956b18141d4c0111b251c60080813..d42d7c58ba07362f3d95b73bd5a6e8b90dab5835 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 1
 cl_playerdetailreduction 0
 gl_flashblend 0
 gl_picmip -1
+gl_texturecompression_2d 0
+gl_texturecompression_sky 0
 mod_q3bsp_nolightmaps 0
 r_bloom 1
 r_coronas 1
diff --git a/gfx/hud/default/as_defend.tga b/gfx/hud/default/as_defend.tga
new file mode 100644 (file)
index 0000000..5aca85e
Binary files /dev/null and b/gfx/hud/default/as_defend.tga differ
diff --git a/gfx/hud/default/as_destroy.tga b/gfx/hud/default/as_destroy.tga
new file mode 100644 (file)
index 0000000..7c779a1
Binary files /dev/null and b/gfx/hud/default/as_destroy.tga differ
diff --git a/gfx/hud/luma/as_defend.tga b/gfx/hud/luma/as_defend.tga
new file mode 100644 (file)
index 0000000..5aca85e
Binary files /dev/null and b/gfx/hud/luma/as_defend.tga differ
diff --git a/gfx/hud/luma/as_destroy.tga b/gfx/hud/luma/as_destroy.tga
new file mode 100644 (file)
index 0000000..7c779a1
Binary files /dev/null and b/gfx/hud/luma/as_destroy.tga differ
index e2e83ae7588ba17ef77aa1f1278f29a69901111a..b90d291fb40646d6ffdbcd7e5845b3835b63c12c 100644 (file)
Binary files a/gfx/hud/luma/ok_weapon_rail.tga and b/gfx/hud/luma/ok_weapon_rail.tga differ
index f5fb92e13ee7bcc11b2809755883a44531fe0b18..b0e7bf9327d5d95350ed74ec1f7589171882963b 100644 (file)
Binary files a/gfx/hud/luma/ok_weapon_shotgun.tga and b/gfx/hud/luma/ok_weapon_shotgun.tga differ
index 5aee32ab545a47884f50cd00ce4248e8cb35ab3c..cb26a1657dd0f04c2775e9d9323327885a5cc918 100644 (file)
Binary files a/gfx/hud/luma/ok_weapon_smg.tga and b/gfx/hud/luma/ok_weapon_smg.tga differ
index c36c3f5e7e587989e23d5d7db7b0e5039f216d75..cb0414cc1ea32fb1881fa8de3f13bbca501de60f 100644 (file)
Binary files a/gfx/hud/luma/weaponhmg.tga and b/gfx/hud/luma/weaponhmg.tga differ
index 643c5cafee679e92a84f4a60c28849cac75eb62e..74019d86f9ec8d079f59badbb83cd17a2afbd9b9 100644 (file)
Binary files a/gfx/hud/luma/weaponrpc.tga and b/gfx/hud/luma/weaponrpc.tga differ
index 65ce9094219c56f80574f2735befda22cf3c46bd..e16e0b878637b50dd21f71c361f88866b5c54379 100644 (file)
@@ -1,25 +1,25 @@
-ko    Korean "한국의" 33%
-ast   Asturian "Asturianu" 73%
+ast   "Asturian" "Asturianu" 73%
+de    "German" "Deutsch" 99%
+de_CH "German (Switzerland)" "Deutsch (Schweiz)" 99%
+en    "English" "English" 100%
+en_AU "English (Australia)" "English (Australia)" 86%
+es    "Spanish" "Español" 99%
+fr    "French" "Français" 99%
+ga    "Irish" "Irish" 35%
+it    "Italian" "Italiano" 99%
+hu    "Hungarian" "Magyar" 55%
+nl    "Dutch" "Nederlands" 70%
+pl    "Polish" "Polski" 81%
+pt    "Portuguese" "Português" 98%
+pt_BR "Portuguese (Brazil)" "Português (Brasil)" 99%
+ro    "Romanian" "Romana" 83%
+fi    "Finnish" "Suomi" 33%
+el    "Greek" "Ελληνική" 33%
+be    "Belarusian" "Беларуская" 61%
+bg    "Bulgarian" "Български" 68%
+ru    "Russian" "Русский" 99%
+sr    "Serbian" "Српски" 71%
+uk    "Ukrainian" "Українська" 57%
 zh_CN "Chinese (China)" "中文" 62%
-de    German "Deutsch"
-de_CH German "Deutsch (Schweiz)"
-en    English "English"
-en_AU English "English (Australia)" 86%
-es    Spanish "Español" 99%
-fr    French "Français"
-ga    Irish "Irish" 35%
-it    Italian "Italiano"
-hu    Hungarian "Magyar" 55%
-nl    Dutch "Nederlands" 70%
-pl    Polish "Polski" 81%
-pt    Portuguese "Português"
-pt_BR pt_BR "pt_BR" 99%
-ro    Romanian "Romana" 83%
-fi    Finnish "Suomi" 33%
 zh_TW "Chinese (Taiwan)" "國語" 68%
-el    Greek "Ελληνική" 33%
-be    Belarusian "Беларуская" 61%
-bg    Bulgarian "Български" 68%
-ru    Russian "Русский"
-sr    Serbian "Српски" 71%
-uk    Ukrainian "Українська" 57%
+ko    "Korean" "한국의" 33%
index 27b579027f93063f207b8fbf849e538a7ea4dff3..efdb0b2b075859d0ae67937c7dda6b8bf878f752 100644 (file)
@@ -10,3 +10,4 @@ bone_aim1 0.4 spine4
 bone_aim2 0.35 bip01 r hand
 bone_weapon bip01 r hand
 fixbone 1
+hidden 1
index 44843b7058baf5ccd13a0e37c88694b99620f9a1..fbc6b672c39d97411a589b4165d5ef2fc0b43095 100644 (file)
@@ -1,4 +1,4 @@
-name Gak Masked
+name Gak
 species alien
 sex Male
 weight 87
index 2610d2b92db356797a22a0b52605efc304c05f41..4a35d9099e9daff55753fd47e1a2157bbaaa4f0f 100644 (file)
@@ -11,3 +11,4 @@ bone_aim2 0.2 upperarm_L
 bone_aim3 0.35 bip01 r hand
 bone_weapon bip01 r hand
 fixbone 1
+hidden 1
index c997d01f36488d7771766fe38956f883b8bcc9bc..76ca617ba11dde4fba964e2babdaf156df10f5ef 100644 (file)
@@ -10,3 +10,4 @@ bone_aim1 0.4 spine4
 bone_aim2 0.35 bip01 r hand
 bone_weapon bip01 r hand
 fixbone 1
+hidden 1
index feb9b871b0d9170ac4356bcec4480fc3212f3bf7..143b5c0e25d71a270007f14e8864b6a6ad99fd9d 100644 (file)
@@ -235,7 +235,6 @@ seta notification_INFO_ITEM_WEAPON_PRIMORSEC "0" "0 = off, 1 = print to console,
 seta notification_INFO_ITEM_WEAPON_UNAVAILABLE "0" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_JETPACK_NOFUEL "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 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_CONNECT_TEAM "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_JOIN_PLAY "1" "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_KEEPAWAY_DROPPED "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
index 8ae771f1cf468a9ac21ec05d4b94cdc4e2782708..61354633d517a6b9d04acc7a0ec66f0fc0ef199f 100644 (file)
@@ -1,5 +1,5 @@
 g_mod_physics Xonotic
-// current Xonotic physics
+// Xonotic 0.7 physics
 
 sv_gravity 800
 sv_maxspeed 360
index 8eb3ca1dcb1a623111fc2a7a095d31ff946ebdc0..9c63f431267b47977c5303182ca9600f22008c95 100644 (file)
@@ -39,13 +39,13 @@ float autocvar_cl_effects_lightningarc_drift_end;
 float autocvar_cl_effects_lightningarc_drift_start;
 float autocvar_cl_effects_lightningarc_segmentlength;
 bool autocvar_cl_effects_lightningarc_simple;
-int autocvar_cl_gentle;
+bool autocvar_cl_gentle;
 int autocvar_cl_gentle_damage;
 int autocvar_cl_gentle_gibs;
 int autocvar_cl_gentle_messages;
 float autocvar_cl_gibs_damageforcescale = 3.5;
 float autocvar_cl_gibs_lifetime = 14;
-float autocvar_cl_gibs_maxcount = 100;
+int autocvar_cl_gibs_maxcount = 100;
 bool autocvar_cl_gibs_sloppy = 1;
 float autocvar_cl_gibs_ticrate = 0.1;
 float autocvar_cl_gibs_velocity_random = 1;
@@ -395,12 +395,12 @@ string autocvar_hud_skin;
 float autocvar_menu_mouse_speed;
 string autocvar_menu_skin;
 int autocvar_r_fakelight;
-int autocvar_r_fullbright;
+bool autocvar_r_fullbright;
 float autocvar_r_letterbox;
 string autocvar_scoreboard_columns;
 bool autocvar_v_flipped;
-float autocvar_vid_conheight;
-float autocvar_vid_conwidth;
+int autocvar_vid_conheight;
+int autocvar_vid_conwidth;
 float autocvar_vid_pixelheight;
 float autocvar_viewsize;
 bool autocvar_cl_eventchase_vehicle = 1;
index 034bb6336680e7ead16421fcaf5fba0c8f78d69c..c4b1ec041126310346a099b3f6b87546097df94a 100644 (file)
@@ -43,7 +43,7 @@ void DrawDebugModel(entity this)
 
 void LocalCommand_blurtest(int request)
 {
-    TC(int, request);
+       TC(int, request);
        // Simple command to work with postprocessing temporarily... possibly completely pointless, the glsl shader is used for a real feature now...
        // Anyway, to enable it, just compile the client with -DBLURTEST and then you can use the command.
 
@@ -79,7 +79,7 @@ void LocalCommand_blurtest(int request)
 
 void LocalCommand_boxparticles(int request, int argc)
 {
-    TC(int, request); TC(int, argc);
+       TC(int, request); TC(int, argc);
        switch (request)
        {
                case CMD_REQUEST_COMMAND:
@@ -135,7 +135,7 @@ void LocalCommand_boxparticles(int request, int argc)
 
 void LocalCommand_create_scrshot_ent(int request)
 {
-    TC(int, request);
+       TC(int, request);
        switch (request)
        {
                case CMD_REQUEST_COMMAND:
@@ -175,7 +175,7 @@ void LocalCommand_create_scrshot_ent(int request)
 
 void LocalCommand_debugmodel(int request, int argc)
 {
-    TC(int, request); TC(int, argc);
+       TC(int, request); TC(int, argc);
        switch (request)
        {
                case CMD_REQUEST_COMMAND:
@@ -205,7 +205,7 @@ void LocalCommand_debugmodel(int request, int argc)
 
 void LocalCommand_handlevote(int request, int argc)
 {
-    TC(int, request); TC(int, argc);
+       TC(int, request); TC(int, argc);
        switch (request)
        {
                case CMD_REQUEST_COMMAND:
@@ -255,7 +255,7 @@ void LocalCommand_handlevote(int request, int argc)
 
 void LocalCommand_hud(int request, int argc)
 {
-    TC(int, request); TC(int, argc);
+       TC(int, request); TC(int, argc);
        switch (request)
        {
                case CMD_REQUEST_COMMAND:
@@ -325,7 +325,8 @@ void LocalCommand_hud(int request, int argc)
 
                                case "clickradar":
                                {
-                                       HUD_Radar_Show_Maximized(!hud_panel_radar_mouse, 1);
+                                       if(!isdemo())
+                                               HUD_Radar_Show_Maximized(!hud_panel_radar_mouse, 1);
                                        return;
                                }
                        }
@@ -350,7 +351,7 @@ void LocalCommand_hud(int request, int argc)
 
 void LocalCommand_localprint(int request, int argc)
 {
-    TC(int, request); TC(int, argc);
+       TC(int, request); TC(int, argc);
        switch (request)
        {
                case CMD_REQUEST_COMMAND:
@@ -377,7 +378,7 @@ void LocalCommand_localprint(int request, int argc)
 
 void LocalCommand_mv_download(int request, int argc)
 {
-    TC(int, request); TC(int, argc);
+       TC(int, request); TC(int, argc);
        switch (request)
        {
                case CMD_REQUEST_COMMAND:
@@ -404,7 +405,7 @@ void LocalCommand_mv_download(int request, int argc)
 
 void LocalCommand_sendcvar(int request, int argc)
 {
-    TC(int, request); TC(int, argc);
+       TC(int, request); TC(int, argc);
        switch (request)
        {
                case CMD_REQUEST_COMMAND:
index d8f6d26a33895e91fd40fb6a8d1b42e723de8575..035ba2a1647c29a2445ca54d73022670536cfed3 100644 (file)
@@ -362,7 +362,7 @@ void CSQCPlayer_AnimDecide_PostUpdate(entity this, bool isnew)
 }
 int CSQCPlayer_FallbackFrame(entity this, int f)
 {
-    TC(int, f);
+       TC(int, f);
        if(frameduration(this.modelindex, f) > 0)
                return f; // goooooood
        if(frameduration(this.modelindex, 1) <= 0)
index 9a5335eff06b7c4ca56a73b17d3324b2a2b9618e..22cbc1a2df32b072905fa8ce9caee5de4f256dc4 100644 (file)
@@ -5,7 +5,7 @@
 float          scoreboard_showscores;
 float          scoreboard_showaccuracy;
 .string                message;
-.int           renderflags;
+.float         renderflags;
 // float               coop;
 // float               deathmatch;
 
@@ -16,7 +16,6 @@ float         dmg_take;
 // Darkplaces Render Modifications
 #if 0
 .float alpha;
-.float renderflags;
 .vector colormod;
 .float scale;
 #endif
index 2b8eed95f7705578fc5ae34a083e8187c0f45a0b..2becced8e0cbcda94ad910946fc4480939b21856 100644 (file)
@@ -75,14 +75,14 @@ vector HUD_Get_Num_Color (float hp, float maxvalue)
 
 float HUD_GetRowCount(int item_count, vector size, float item_aspect)
 {
-    TC(int, item_count);
+       TC(int, item_count);
        float aspect = size_y / size_x;
        return bound(1, floor((sqrt(4 * item_aspect * aspect * item_count + aspect * aspect) + aspect + 0.5) / 2), item_count);
 }
 
 vector HUD_GetTableSize_BestItemAR(int item_count, vector psize, float item_aspect)
 {
-    TC(int, item_count);
+       TC(int, item_count);
        float columns, rows;
        float ratio, best_ratio = 0;
        float best_columns = 1, best_rows = 1;
@@ -180,7 +180,7 @@ void HUD_Panel_LoadCvars()
 //basically the same code of draw_ButtonPicture and draw_VertButtonPicture for the menu
 void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag)
 {
-    TC(bool, vertical); TC(int, drawflag);
+       TC(bool, vertical); TC(int, drawflag);
        if(!length_ratio || !theAlpha)
                return;
        if(length_ratio > 1)
@@ -287,7 +287,7 @@ void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, flo
 
 void HUD_Panel_DrawHighlight(vector pos, vector mySize, vector color, float theAlpha, int drawflag)
 {
-    TC(int, drawflag);
+       TC(int, drawflag);
        if(!theAlpha)
                return;
 
@@ -308,7 +308,7 @@ void HUD_Panel_DrawHighlight(vector pos, vector mySize, vector color, float theA
 
 void DrawNumIcon_expanding(vector myPos, vector mySize, float theTime, string icon, bool vertical, int icon_right_align, vector color, float theAlpha, float fadelerp)
 {
-    TC(bool, vertical); TC(int, icon_right_align);
+       TC(bool, vertical); TC(int, icon_right_align);
        vector newPos = '0 0 0', newSize = '0 0 0';
        vector picpos, numpos;
 
@@ -388,7 +388,7 @@ void DrawNumIcon_expanding(vector myPos, vector mySize, float theTime, string ic
 
 void DrawNumIcon(vector myPos, vector mySize, float theTime, string icon, bool vertical, int icon_right_align, vector color, float theAlpha)
 {
-    TC(bool, vertical); TC(int, icon_right_align);
+       TC(bool, vertical); TC(int, icon_right_align);
        DrawNumIcon_expanding(myPos, mySize, theTime, icon, vertical, icon_right_align, color, theAlpha, 0);
 }
 
index 01ce50cdbb6f87e03291c9f57232dc683aff76c9..ce700586caad1efe174acea70a0a85f06b2a0ced 100644 (file)
@@ -22,7 +22,7 @@ void DrawNadeProgressBar(vector myPos, vector mySize, float progress, vector col
 
 void DrawAmmoItem(vector myPos, vector mySize, int ammoType, bool isCurrent, bool isInfinite)
 {
-    TC(bool, isCurrent); TC(bool, isInfinite);
+       TC(bool, isCurrent); TC(bool, isInfinite);
        if(ammoType == RESOURCE_NONE)
                return;
 
index f8f70c8189e671de3cb01fd3d4c4a8aab3e7745a..90a496e0d175962f8dae41d4f75beec0346010b9 100644 (file)
@@ -20,7 +20,7 @@ bool centerprint_showing;
 
 void centerprint_generic(int new_id, string strMessage, float duration, int countdown_num)
 {
-    TC(int, new_id); TC(int, countdown_num);
+       TC(int, new_id); TC(int, countdown_num);
        //printf("centerprint_generic(%d, '%s^7', %d, %d);\n", new_id, strMessage, duration, countdown_num);
        int i, j;
 
@@ -94,7 +94,7 @@ void centerprint_generic(int new_id, string strMessage, float duration, int coun
 
 void centerprint_kill(int id)
 {
-    TC(int, id);
+       TC(int, id);
        centerprint_generic(id, "", 0, 0);
 }
 
index 89b8a8c188b4a981774ed1c173b98e8215c62a78..87e4a7fb251af875266a9ea72c82cdd6449e1f91 100644 (file)
@@ -13,7 +13,7 @@ bool mod_active; // is there any active mod icon?
 
 void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
 {
-    TC(int, layout); TC(int, i);
+       TC(int, layout); TC(int, i);
        int stat = -1;
        string pic = "";
        vector color = '0 0 0';
@@ -626,7 +626,7 @@ void HUD_Mod_Race(vector pos, vector mySize)
 
 void DrawDomItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
 {
-    TC(int, layout); TC(int, i);
+       TC(int, layout); TC(int, i);
        float stat = -1;
        string pic = "";
        vector color = '0 0 0';
index dd574cf9b039c4b69d6654792a36525e7c54ba57..947bfd53b3ee1075063b72a489ece3b981811753 100644 (file)
@@ -47,7 +47,7 @@ void addPowerupItem(string name, string icon, vector color, float currentTime, f
 
 int getPowerupItemAlign(int align, int column, int row, int columns, int rows, bool isVertical)
 {
-    TC(int, align); TC(int, column); TC(int, row); TC(int, columns); TC(int, rows); TC(bool, isVertical);
+       TC(int, align); TC(int, column); TC(int, row); TC(int, columns); TC(int, rows); TC(bool, isVertical);
        if(align < 2)
                return align;
 
index 29f69b3d4d9c506efc1676f48055af6c13011c4e..e7e3c6d65241b9b7a207faa2aedcaa9603ac4009 100644 (file)
@@ -43,7 +43,7 @@ float QuickMenu_TimeOut;
 // if s1 is not empty s will be displayed as command otherwise as submenu
 void QuickMenu_Page_LoadEntry(int i, string s, string s1)
 {
-    TC(int, i);
+       TC(int, i);
        //LOG_INFOF("^xc80 entry %d: %s, %s\n", i, s, s1);
        strcpy(QuickMenu_Page_Description[i], s);
        strcpy(QuickMenu_Page_Command[i], s1);
@@ -51,7 +51,7 @@ void QuickMenu_Page_LoadEntry(int i, string s, string s1)
 
 void QuickMenu_Page_ClearEntry(int i)
 {
-    TC(int, i);
+       TC(int, i);
        strfree(QuickMenu_Page_Description[i]);
        strfree(QuickMenu_Page_Command[i]);
        QuickMenu_Page_Command_Type[i] = 0;
@@ -105,7 +105,7 @@ bool QuickMenu_Open(string mode, string submenu, string file)
                while((s = fgets(fh)) && QuickMenu_Buffer_Size < QUICKMENU_BUFFER_MAXENTRIES)
                {
                        // first skip invalid entries, so we don't check them anymore
-                       float argc;
+                       int argc;
                        argc = tokenize_console(s);
                        if(argc == 0 || argv(0) == "")
                                continue;
@@ -225,7 +225,7 @@ bool QuickMenu_IsOpened()
 
 bool HUD_Quickmenu_PlayerListEntries_Create(string cmd, int teamplayers, bool without_me)
 {
-    TC(int, teamplayers); TC(bool, without_me);
+       TC(int, teamplayers); TC(bool, without_me);
        int i;
        for(i = 0; i < QUICKMENU_MAXLINES; ++i)
                QuickMenu_Page_ClearEntry(i);
@@ -250,7 +250,7 @@ bool HUD_Quickmenu_PlayerListEntries_Create(string cmd, int teamplayers, bool wi
 int QuickMenu_Buffer_Index_Prev;
 bool QuickMenu_Page_Load(string target_submenu, bool new_page)
 {
-    TC(bool, new_page);
+       TC(bool, new_page);
        string s = string_null, cmd = string_null, z_submenu;
 
        if (new_page == 0)
@@ -361,7 +361,7 @@ bool QuickMenu_Page_Load(string target_submenu, bool new_page)
 
 bool QuickMenu_ActionForNumber(int num)
 {
-    TC(int, num);
+       TC(int, num);
        if (!QuickMenu_IsLastPage)
        {
                if (num < 0 || num >= QUICKMENU_MAXLINES)
@@ -389,7 +389,7 @@ bool QuickMenu_ActionForNumber(int num)
 
 void QuickMenu_Page_ActiveEntry(int entry_num)
 {
-    TC(int, entry_num);
+       TC(int, entry_num);
        QuickMenu_Page_ActivatedEntry = entry_num;
        QuickMenu_Page_ActivatedEntry_Time = time + 0.1;
        if(QuickMenu_Page_Command[QuickMenu_Page_ActivatedEntry])
@@ -407,7 +407,7 @@ void QuickMenu_Page_ActiveEntry(int entry_num)
 
 bool QuickMenu_InputEvent(int bInputType, float nPrimary, float nSecondary)
 {
-    TC(int, bInputType);
+       TC(int, bInputType);
        // we only care for keyboard events
        if(bInputType == 2)
                return false;
@@ -748,7 +748,7 @@ void HUD_QuickMenu()
 
 void HUD_Quickmenu_PlayerListEntries(string cmd, int teamplayers, bool without_me)
 {
-    TC(int, teamplayers); TC(bool, without_me);
+       TC(int, teamplayers); TC(bool, without_me);
        entity pl;
        if(teamplayers && !team_count)
                return;
index bd94520d4e4292972e51277c0f27d6fc7fd7cd75..65073d9fed09700f5c8aebc6dfd6c322f6a05294 100644 (file)
@@ -19,7 +19,7 @@ bool HUD_Radar_Clickable()
 
 void HUD_Radar_Show_Maximized(bool doshow, bool clickable)
 {
-    TC(bool, doshow);
+       TC(bool, doshow);
        hud_panel_radar_maximized = doshow;
        hud_panel_radar_temp_hidden = 0;
 
@@ -56,7 +56,7 @@ void HUD_Radar_Hide_Maximized()
 
 float HUD_Radar_InputEvent(int bInputType, float nPrimary, float nSecondary)
 {
-    TC(int, bInputType);
+       TC(int, bInputType);
        if(!hud_panel_radar_maximized || !hud_panel_radar_mouse ||
                autocvar__hud_configure || mv_active)
                return false;
index 5b8964d0d3962a913033d672c7ad4366d9605b06..32ccccfca3355dedfa235c20e96f316ee61ed2b4 100644 (file)
@@ -175,7 +175,7 @@ void Scoreboard_UpdatePlayerTeams()
 
 int Scoreboard_CompareScore(int vl, int vr, int f)
 {
-    TC(int, vl); TC(int, vr); TC(int, f);
+       TC(int, vl); TC(int, vr); TC(int, f);
        if(f & SFL_ZERO_IS_WORST)
        {
                if(vl == 0 && vr != 0)
@@ -294,8 +294,11 @@ void Cmd_Scoreboard_Help()
 {
        LOG_INFO(_("You can modify the scoreboard using the ^2scoreboard_columns_set command."));
        LOG_INFO(_("Usage:"));
-       LOG_INFO("^2scoreboard_columns_set default");
-       LOG_INFO(_("^2scoreboard_columns_set ^7field1 field2 ..."));
+       LOG_INFO("^2scoreboard_columns_set ^3default");
+       LOG_INFO(_("^2scoreboard_columns_set ^3field1 field2 ..."));
+       LOG_INFO(_("^2scoreboard_columns_set ^7without arguments reads the arguments from the cvar scoreboard_columns"));
+       LOG_INFO(_("  ^5Note: ^7scoreboard_columns_set without arguments is executed on every map start"));
+       LOG_INFO(_("^2scoreboard_columns_set ^3expand_default ^7loads default layout and expands it into the cvar scoreboard_columns so you can edit it"));
        LOG_INFO(_("You can use a ^3|^7 to start the right-aligned fields."));
        LOG_INFO(_("The following field names are recognized (case insensitive):"));
        LOG_INFO("");
@@ -378,7 +381,7 @@ void Cmd_Scoreboard_Help()
 
 void Cmd_Scoreboard_SetFields(int argc)
 {
-    TC(int, argc);
+       TC(int, argc);
        int i, slash;
        string str, pattern;
        bool have_name = false, have_primary = false, have_secondary = false, have_separator = false;
@@ -401,8 +404,12 @@ void Cmd_Scoreboard_SetFields(int argc)
 
        if(argc == 3)
        {
-               if(argv(2) == "default")
+               if(argv(2) == "default" || argv(2) == "expand_default")
+               {
+                       if(argv(2) == "expand_default")
+                               cvar_set("scoreboard_columns", SCOREBOARD_DEFAULT_COLUMNS);
                        argc = tokenizebyseparator(strcat("0 1 ", SCOREBOARD_DEFAULT_COLUMNS), " ");
+               }
                else if(argv(2) == "all")
                {
                        string s = "ping pl name |"; // scores without a label
@@ -709,7 +716,7 @@ float sbt_fixcolumnwidth_marginlen;
 
 string Scoreboard_FixColumnWidth(int i, string str)
 {
-    TC(int, i);
+       TC(int, i);
        float f;
        vector sz;
 
@@ -833,7 +840,7 @@ vector Scoreboard_DrawHeader(vector pos, vector rgb, bool other_players)
 
 void Scoreboard_DrawItem(vector item_pos, vector rgb, entity pl, bool is_self, int pl_number)
 {
-    TC(bool, is_self); TC(int, pl_number);
+       TC(bool, is_self); TC(int, pl_number);
        string str;
        bool is_spec = (entcs_GetTeam(pl.sv_entnum) == NUM_SPECTATOR);
 
index a560b74c74ab616e33fc4ac497741a6e22cf4f48..b2bda4829e1084b71652488f78b1444ca10b203e 100644 (file)
@@ -4,7 +4,7 @@
 bool scoreboard_active;
 float scoreboard_fade_alpha;
 
-void Cmd_Scoreboard_SetFields(float argc);
+void Cmd_Scoreboard_SetFields(int argc);
 void Scoreboard_Draw();
 void Scoreboard_InitScores();
 void Scoreboard_UpdatePlayerTeams();
index 5d75c7dd2a4182fe19d9a4ec67d2940a3d877174..8bf11cf1ac93d3994840bb64b96bac5ce993317d 100644 (file)
@@ -11,7 +11,7 @@
 entity weaponorder[Weapons_MAX];
 void weaponorder_swap(int i, int j, entity pass)
 {
-    TC(int, i); TC(int, j);
+       TC(int, i); TC(int, j);
        entity h = weaponorder[i];
        weaponorder[i] = weaponorder[j];
        weaponorder[j] = h;
@@ -20,7 +20,7 @@ void weaponorder_swap(int i, int j, entity pass)
 string weaponorder_cmp_str;
 int weaponorder_cmp(int i, int j, entity pass)
 {
-    TC(int, i); TC(int, j);
+       TC(int, i); TC(int, j);
        int ai = strstrofs(weaponorder_cmp_str, sprintf(" %d ", weaponorder[i].m_id), 0);
        int aj = strstrofs(weaponorder_cmp_str, sprintf(" %d ", weaponorder[j].m_id), 0);
        return aj - ai; // the string is in REVERSE order (higher prio at the right is what we want, but higher prio first is the string)
index 218df18a474fc47746e8a928f77e164ecece995f..6844b1e078d7ad30380aae9913c1301832a5bc1d 100644 (file)
@@ -228,9 +228,9 @@ void Shutdown()
 }
 
 .float has_team;
-float SetTeam(entity o, int Team)
+bool SetTeam(entity o, int Team)
 {
-    TC(int, Team);
+       TC(int, Team);
        devassert_once(Team);
        entity tm;
        if(teamplay)
@@ -577,14 +577,14 @@ NET_HANDLE(ENT_CLIENT_NAGGER, bool isnew)
        {
                for(j = 0; j < maxclients; ++j)
                        if(playerslots[j])
-                               playerslots[j].ready = 1;
+                               playerslots[j].ready = true;
                for(i = 1; i <= maxclients; i += 8)
                {
                        f = ReadByte();
                        for(j = i-1, b = BIT(0); b < BIT(8); b <<= 1, ++j)
                                if (!(f & b))
                                        if(playerslots[j])
-                                               playerslots[j].ready = 0;
+                                               playerslots[j].ready = false;
                }
        }
 
@@ -605,7 +605,7 @@ NET_HANDLE(ENT_CLIENT_ELIMINATEDPLAYERS, bool isnew)
        if (sf & 1) {
                for (int j = 0; j < maxclients; ++j) {
                        if (playerslots[j]) {
-                               playerslots[j].eliminated = 1;
+                               playerslots[j].eliminated = true;
                        }
                }
                for (int i = 1; i <= maxclients; i += 8) {
@@ -615,7 +615,7 @@ NET_HANDLE(ENT_CLIENT_ELIMINATEDPLAYERS, bool isnew)
                                if (f & BIT(b)) continue;
                                int j = i - 1 + b;
                                if (playerslots[j]) {
-                                       playerslots[j].eliminated = 0;
+                                       playerslots[j].eliminated = false;
                                }
                        }
                }
index 69c3fa3d2b300eb4f54f6fd2a9bf4b8e68db62bf..8a0e78a0d8126fa7fa78fcca829a5c2af1b1f411 100644 (file)
@@ -9,7 +9,7 @@ vector mi_scale;
 // Minimap
 string minimapname;
 
-float postinit;
+bool postinit;
 entity gametype;
 
 float FONT_USER = 8;
@@ -27,7 +27,7 @@ void Ent_Remove(entity this);
 
 void Gamemode_Init();
 
-float SetTeam(entity pl, float Team);
+bool SetTeam(entity pl, int Team);
 
 vector hud_fontsize;
 
@@ -38,10 +38,10 @@ float grecordtime[RANKINGS_CNT];
 
 entity playerslots[255]; // 255 is engine limit on maxclients
 entity teamslots[17];    // 17 teams (including "spectator team")
-.float gotscores;
+.bool gotscores;
 .entity owner;
-.float ready;
-.float eliminated;
+.bool ready;
+.bool eliminated;
 
 .void(entity) draw;
 IntrusiveList g_drawables;
@@ -64,7 +64,7 @@ bool button_attack2;
 
 float current_viewzoom;
 float zoomin_effect;
-float warmup_stage;
+bool warmup_stage;
 
 void Fog_Force();
 
@@ -73,15 +73,16 @@ string _getcommandkey(string text, string command, bool forcename);
 #define getcommandkey_forcename(cmd_name, command) _getcommandkey(cmd_name, command, true)
 
 string vote_called_vote;
-float ready_waiting;
-float ready_waiting_for_me;
-float vote_waiting;
-float vote_waiting_for_me;
+bool ready_waiting;
+bool ready_waiting_for_me;
+bool vote_waiting;
+bool vote_waiting_for_me;
 
 float current_zoomfraction;
 
-float cs_project_is_b0rked;
-float vid_width, vid_height, vid_pixelheight;
+int cs_project_is_b0rked;
+int vid_width, vid_height;
+float vid_pixelheight;
 
 float camera_active;           // Demo camera is active if set to true
 float chase_active_backup;
index 8412bd757964ffdec471381121b8a923af5a152c..03e94dc7f304238bc916443bc4a6fbef512d7bc7 100644 (file)
@@ -43,7 +43,7 @@ int n_ssdirs;
 
 string MapVote_FormatMapItem(int id, string map, float _count, float maxwidth, vector fontsize)
 {
-    TC(int, id);
+       TC(int, id);
        string pre, post;
        pre = sprintf("%d. ", id+1);
        if(mv_detail)
@@ -64,7 +64,7 @@ string MapVote_FormatMapItem(int id, string map, float _count, float maxwidth, v
 
 vector MapVote_RGB(int id)
 {
-    TC(int, id);
+       TC(int, id);
        if(!(mv_flags[id] & GTV_AVAILABLE))
                return '1 1 1';
        if(id == mv_ownvote)
@@ -77,7 +77,7 @@ vector MapVote_RGB(int id)
 
 void GameTypeVote_DrawGameTypeItem(vector pos, float maxh, float tsize, string gtype, string pic, float _count, int id)
 {
-    TC(int, id);
+       TC(int, id);
        // Find the correct alpha
        float alpha;
        if(!(mv_flags_start[id] & GTV_AVAILABLE))
@@ -189,7 +189,7 @@ void GameTypeVote_DrawGameTypeItem(vector pos, float maxh, float tsize, string g
 
 void MapVote_DrawMapItem(vector pos, float isize, float tsize, string map, string pic, float _count, int id)
 {
-    TC(int, id);
+       TC(int, id);
        vector img_size = '0 0 0';
        string label;
        float text_size;
@@ -264,7 +264,7 @@ void MapVote_DrawMapItem(vector pos, float isize, float tsize, string map, strin
 
 void MapVote_DrawAbstain(vector pos, float isize, float tsize, float _count, int id)
 {
-    TC(int, id);
+       TC(int, id);
        vector rgb;
        float text_size;
        string label;
@@ -281,7 +281,7 @@ void MapVote_DrawAbstain(vector pos, float isize, float tsize, float _count, int
 
 vector MapVote_GridVec(vector gridspec, int i, int m)
 {
-    TC(int, i); TC(int, m);
+       TC(int, i); TC(int, m);
        int r = i % m;
        return
                '1 0 0' * (gridspec.x * r)
@@ -491,7 +491,7 @@ void MapVote_Draw()
 
 void Cmd_MapVote_MapDownload(int argc)
 {
-    TC(int, argc);
+       TC(int, argc);
        entity pak;
 
        if(argc != 2 || !mv_pk3list)
@@ -522,7 +522,7 @@ void Cmd_MapVote_MapDownload(int argc)
 
 void MapVote_CheckPK3(string pic, string pk3, int id)
 {
-    TC(int, id);
+       TC(int, id);
        entity pak;
        pak = spawn();
        pak.netname = pk3;
@@ -544,7 +544,7 @@ void MapVote_CheckPK3(string pic, string pk3, int id)
 
 void MapVote_CheckPic(string pic, string pk3, int id)
 {
-    TC(int, id);
+       TC(int, id);
        // never try to retrieve a pic for the "don't care" 'map'
        if(mv_abstain && id == mv_num_maps - 1)
                return;
@@ -587,7 +587,7 @@ void MapVote_ReadMask()
 
 void MapVote_ReadOption(int i)
 {
-    TC(int, i);
+       TC(int, i);
        string map = strzone(ReadString());
        string pk3 = strzone(ReadString());
        int j = bound(0, ReadByte(), n_ssdirs - 1);
@@ -604,7 +604,7 @@ void MapVote_ReadOption(int i)
 
 void GameTypeVote_ReadOption(int i)
 {
-    TC(int, i);
+       TC(int, i);
        string gt = strzone(ReadString());
 
        mv_maps[i] = gt;
@@ -711,13 +711,13 @@ void MapVote_Init()
 
 void MapVote_SendChoice(int index)
 {
-    TC(int, index);
+       TC(int, index);
        localcmd(strcat("\nimpulse ", ftos(index+1), "\n"));
 }
 
 int MapVote_MoveLeft(int pos)
 {
-    TC(int, pos);
+       TC(int, pos);
        int imp;
        if ( pos < 0 )
                imp = mv_num_maps - 1;
@@ -729,7 +729,7 @@ int MapVote_MoveLeft(int pos)
 }
 int MapVote_MoveRight(int pos)
 {
-    TC(int, pos);
+       TC(int, pos);
        int imp;
        if ( pos < 0 )
                imp = 0;
@@ -741,7 +741,7 @@ int MapVote_MoveRight(int pos)
 }
 int MapVote_MoveUp(int pos)
 {
-    TC(int, pos);
+       TC(int, pos);
        int imp;
        if ( pos < 0 )
                imp = mv_num_maps - 1;
@@ -761,7 +761,7 @@ int MapVote_MoveUp(int pos)
 }
 int MapVote_MoveDown(int pos)
 {
-    TC(int, pos);
+       TC(int, pos);
        int imp;
        if ( pos < 0 )
                imp = 0;
@@ -778,7 +778,7 @@ int MapVote_MoveDown(int pos)
 
 float MapVote_InputEvent(int bInputType, float nPrimary, float nSecondary)
 {
-    TC(int, bInputType);
+       TC(int, bInputType);
        float imp;
 
        if (!mv_active)
index 2f95102a990bf84571b8010cff9b55c674991dca..8a6f542a0a597277cb598b45dff23f335f2ae824 100644 (file)
@@ -3,7 +3,7 @@
 #include <common/constants.qh>
 void MapVote_Draw();
 
-void Cmd_MapVote_MapDownload(float argc);
+void Cmd_MapVote_MapDownload(int argc);
 
 float MapVote_InputEvent(float bInputType, float nPrimary, float nSecondary);
 
index 01409280a4a4c9f535cf18e6c0f7f21b2eb1d8b0..360305601a8b71cfdd345436f213f9eafb5e50ee 100644 (file)
@@ -121,7 +121,7 @@ void RemoveTeam(entity Team)
 
 entity GetTeam(int Team, bool add)
 {
-    TC(int, Team); TC(bool, add);
+       TC(int, Team); TC(bool, add);
        int num = (Team == NUM_SPECTATOR) ? 16 : Team;
        if(teamslots[num])
                return teamslots[num];
@@ -553,7 +553,7 @@ void DrawCircleClippedPic(vector centre, float radi, string pic, float f, vector
 /** engine callback */
 void URI_Get_Callback(int id, int status, string data)
 {
-    TC(int, id); TC(int, status);
+       TC(int, id); TC(int, status);
        if(url_URI_Get_Callback(id, status, data))
        {
                // handled
index bb1b6f919b840c78a2bca6d339245e5b057acbc1..d9c9ab14210353a5490d4e9dc5deadde59763577 100644 (file)
@@ -83,7 +83,7 @@ void skeleton_markbones(entity e)
 
 void skel_set_boneabs(float s, int bone, vector absorg)
 {
-    TC(int, bone);
+       TC(int, bone);
        vector absang = fixedvectoangles2(v_forward, v_up);
 
        vector parentorg = skel_get_boneabs(s, skel_get_boneparent(s, bone));
@@ -113,7 +113,7 @@ void free_skeleton_from_frames(entity e)
 
 void skeleton_from_frames(entity e, bool is_dead)
 {
-    TC(bool, is_dead);
+       TC(bool, is_dead);
        float m = e.modelindex;
        if(!e.skeletonindex)
        {
index c5f1c2fb4b1468b1b50bf997f366987ce675c83f..5d40dbe04eeefb986630eb8c0dc0c8e5c09bf712 100644 (file)
@@ -149,7 +149,7 @@ void draw_teamradar_icon(vector coord, entity icon, entity pingdata, vector rgb,
 
 void draw_teamradar_link(vector start, vector end, int colors)
 {
-    TC(int, colors);
+       TC(int, colors);
        vector c0, c1, norm;
 
        start = teamradar_texcoord_to_2dcoord(teamradar_3dcoord_to_texcoord(start));
index 4d355fb2a177fd5fe102c19ff5b7783381abf227..a7fbe136825b960bb2718fc518183d5d259d8e47 100644 (file)
@@ -491,9 +491,8 @@ vector GetCurrentFov(float fov)
        if(zoomfactor < 1 || zoomfactor > 30)
                zoomfactor = 2.5;
        zoomspeed = autocvar_cl_zoomspeed;
-       if(zoomspeed >= 0)
-       if(zoomspeed < 0.5 || zoomspeed > 16)
-                       zoomspeed = 3.5;
+       if (zoomspeed >= 0 && (zoomspeed < 0.5 || zoomspeed > 16))
+               zoomspeed = 3.5;
 
        zoomdir = button_zoom;
 
@@ -526,7 +525,11 @@ vector GetCurrentFov(float fov)
 
        if(zoomdir) { zoomin_effect = 0; }
 
-       if(camera_active)
+       if (spectatee_status > 0 && STAT(CAMERA_SPECTATOR) == 2)
+       {
+               current_viewzoom = 1;
+       }
+       else if (camera_active)
        {
                current_viewzoom = min(1, current_viewzoom + drawframetime);
        }
@@ -570,10 +573,10 @@ vector GetCurrentFov(float fov)
 
        if(autocvar_cl_velocityzoom_enabled && autocvar_cl_velocityzoom_type) // _type = 0 disables velocity zoom too
        {
-               if(intermission) { curspeed = 0; }
+               if (intermission || (spectatee_status > 0 && STAT(CAMERA_SPECTATOR) == 2))
+                       curspeed = 0;
                else
                {
-
                        makevectors(view_angles);
                        v = pmove_vel;
                        if(csqcplayer)
@@ -1565,7 +1568,7 @@ int lasthud;
 float vh_notice_time;
 void CSQC_UpdateView(entity this, float w, float h)
 {
-    TC(int, w); TC(int, h);
+       TC(int, w); TC(int, h);
        entity e;
        float fov;
        float f;
index 41b97694496616fa4de17b8f73aa2c163cb2fa6d..f4871e7fc6194803adf7fa2a8b9ec1276abc06c3 100644 (file)
@@ -171,7 +171,7 @@ void Projectile_Draw(entity this)
 
 void loopsound(entity e, int ch, Sound samp, float vol, float attn)
 {
-    TC(int, ch);
+       TC(int, ch);
        if (e.silent)
                return;
 
index 3bdc8725c2803b5c9c27f6f0f30c9841d6ea8294..25c008d260d12329b2e16aed6dfdf97fdaf0973d 100644 (file)
@@ -29,4 +29,4 @@ void CampaignFile_Unload();
 
 // Sets up the campaign for the n-th array item (meaning: campaign_offset+nth
 // level) using localcmd()
-void CampaignSetup(float n);
+void CampaignSetup(int n);
index bc26203399bf44aace75bcff27b303f2caa738b0..4f099b53301010a383b9efaa5a27d9e2e5ceebaf 100644 (file)
@@ -52,8 +52,6 @@ float CampaignFile_Load(int offset, float n)
                a = ""; \
        else \
                ++i
-// What you're seeing here is what people will do when your compiler supports
-// C-style macros but no line continuations.
 
                                i = -1; // starts at -1 so I don't need postincrement; that is, i points to BEFORE the current arg!
                                CAMPAIGN_GETARG; campaign_gametype[campaign_entries] = strzone(a);
index 349d492da82b4169113ecde8989e764f06690f22..26308b89db807514f60b36ea236b14ccbc32fd9c 100644 (file)
@@ -8,6 +8,6 @@ CLASS(Command, Object)
        ATTRIB(Command, m_description, string);
        METHOD(Command, m_invokecmd, void(Command this, int request, entity caller, int arguments, string command))
        {
-        TC(Command, this);
+               TC(Command, this);
        }
 ENDCLASS(Command)
index c58a3df75a50d83e55731bc5955020f999781007..08c20072c7daefef87349b840e62b843b8ae54eb 100644 (file)
@@ -57,7 +57,7 @@ void Curl_URI_Get_Callback(int id, float status, string data)
 //  Command Sub-Functions
 // =======================
 
-void GenericCommand_addtolist(float request, float argc)
+void GenericCommand_addtolist(int request, int argc)
 {
        switch(request)
        {
@@ -97,7 +97,7 @@ void GenericCommand_addtolist(float request, float argc)
        }
 }
 
-void GenericCommand_qc_curl(float request, float argc)
+void GenericCommand_qc_curl(int request, int argc)
 {
        switch(request)
        {
@@ -169,7 +169,7 @@ void GenericCommand_qc_curl(float request, float argc)
        }
 }
 
-GENERIC_COMMAND(dumpcommands, "Dump all commands on the program to *_cmd_dump.txt")
+GENERIC_COMMAND(dumpcommands, "Dump all commands on the program to <program>_cmd_dump.txt")
 {
        switch(request)
        {
@@ -184,23 +184,28 @@ GENERIC_COMMAND(dumpcommands, "Dump all commands on the program to *_cmd_dump.tx
                                #ifdef SVQC
                                        CMD_Write("dump of server console commands:\n");
                                        GameCommand_macro_write_aliases(fh);
+                                       CMD_Write("\n");
 
-                                       CMD_Write("\ndump of networked client only commands:\n");
+                                       CMD_Write("dump of networked client only commands:\n");
                                        ClientCommand_macro_write_aliases(fh);
+                                       CMD_Write("\n");
 
-                                       CMD_Write("\ndump of common commands:\n");
+                                       CMD_Write("dump of common commands:\n");
                                        CommonCommand_macro_write_aliases(fh);
+                                       CMD_Write("\n");
 
-                                       CMD_Write("\ndump of ban commands:\n");
+                                       CMD_Write("dump of ban commands:\n");
                                        BanCommand_macro_write_aliases(fh);
+                                       CMD_Write("\n");
                                #endif
 
                                #ifdef CSQC
                                        CMD_Write("dump of client commands:\n");
                                        LocalCommand_macro_write_aliases(fh);
+                                       CMD_Write("\n");
                                #endif
 
-                               CMD_Write("\ndump of generic commands:\n");
+                               CMD_Write("dump of generic commands:\n");
                                GenericCommand_macro_write_aliases(fh);
 
                                LOG_INFO("Completed dump of aliases in ^2data/data/", GetProgramCommandPrefix(), "_dump.txt^7.");
@@ -224,7 +229,7 @@ GENERIC_COMMAND(dumpcommands, "Dump all commands on the program to *_cmd_dump.tx
        }
 }
 
-void GenericCommand_maplist(float request, float argc)
+void GenericCommand_maplist(int request, int argc)
 {
        switch(request)
        {
@@ -307,7 +312,7 @@ void GenericCommand_maplist(float request, float argc)
        }
 }
 
-void GenericCommand_nextframe(float request, float arguments, string command)
+void GenericCommand_nextframe(int request, float arguments, string command)
 {
        switch(request)
        {
@@ -327,7 +332,7 @@ void GenericCommand_nextframe(float request, float arguments, string command)
        }
 }
 
-void GenericCommand_removefromlist(float request, float argc)
+void GenericCommand_removefromlist(int request, int argc)
 {
        switch(request)
        {
@@ -362,7 +367,7 @@ void GenericCommand_removefromlist(float request, float argc)
        }
 }
 
-void GenericCommand_restartnotifs(float request)
+void GenericCommand_restartnotifs(int request)
 {
        switch(request)
        {
@@ -410,7 +415,7 @@ void GenericCommand_restartnotifs(float request)
        }
 }
 
-void GenericCommand_settemp(float request, float argc)
+void GenericCommand_settemp(int request, int argc)
 {
        switch(request)
        {
@@ -441,7 +446,7 @@ void GenericCommand_settemp(float request, float argc)
        }
 }
 
-void GenericCommand_settemp_restore(float request, float argc)
+void GenericCommand_settemp_restore(int request, int argc)
 {
        switch(request)
        {
@@ -468,7 +473,7 @@ void GenericCommand_settemp_restore(float request, float argc)
        }
 }
 
-void GenericCommand_runtest(float request, float argc)
+void GenericCommand_runtest(int request, int argc)
 {
        switch(request)
        {
@@ -496,7 +501,7 @@ void GenericCommand_runtest(float request, float argc)
 
 /* use this when creating a new command, making sure to place it in alphabetical order... also,
 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
-void GenericCommand_(float request)
+void GenericCommand_(int request)
 {
        switch(request)
        {
@@ -534,7 +539,7 @@ void GenericCommand_macro_help()
        FOREACH(GENERIC_COMMANDS, true, LOG_INFOF("  ^2%s^7: %s", it.m_name, it.m_description));
 }
 
-float GenericCommand_macro_command(float argc, string command)
+float GenericCommand_macro_command(int argc, string command)
 {
        string c = strtolower(argv(0));
        FOREACH(GENERIC_COMMANDS, it.m_name == c, {
@@ -544,7 +549,7 @@ float GenericCommand_macro_command(float argc, string command)
        return false;
 }
 
-float GenericCommand_macro_usage(float argc)
+float GenericCommand_macro_usage(int argc)
 {
        string c = strtolower(argv(1));
        FOREACH(GENERIC_COMMANDS, it.m_name == c, {
@@ -567,7 +572,7 @@ void GenericCommand_macro_write_aliases(float fh)
 
 float GenericCommand(string command)
 {
-       float argc = tokenize_console(command);
+       int argc = tokenize_console(command);
        float n, j, f, i;
        string s, s2, c;
        vector rgb;
index b39c79901457de6a77b18d42ed93ac5113d71d61..68aa0ae88af0d1b0b1deafc9eee5f46735da808a 100644 (file)
@@ -9,9 +9,9 @@
 
 void GenericCommand_macro_help();
 
-float GenericCommand_macro_command(float argc, string command);
+float GenericCommand_macro_command(int argc, string command);
 
-float GenericCommand_macro_usage(float argc);
+float GenericCommand_macro_usage(int argc);
 
 void GenericCommand_macro_write_aliases(float fh);
 
index 7e1c4f52eb2879e58f47328c9402f33879398cd5..0998fad9dbd4ea4ea02ed815840ff18a8b3f548f 100644 (file)
@@ -53,7 +53,7 @@ float rpn_popf() { return stof(rpn_pop()); }
 void rpn_pushf(float f) { return rpn_push(sprintf("%.9g", f)); }
 void rpn_setf(float f) { return rpn_set(sprintf("%.9g", f)); }
 
-void GenericCommand_rpn(float request, float argc, string command)
+void GenericCommand_rpn(int request, int argc, string command)
 {
        switch(request)
        {
index ba028e248431806131679777bf116d8430d4f07a..75f5ba65d88ce2f06682fdce971dbd4671cda72d 100644 (file)
@@ -11,4 +11,4 @@ int rpn_error;
 int rpn_sp;
 string rpn_stack[MAX_RPN_STACK];
 
-void GenericCommand_rpn(float request, float argc, string command);
+void GenericCommand_rpn(int request, int argc, string command);
index 41c5d3017eada07992e8ba6ae102827da85525d4..b1dea6dcc431a84c1063d36f567047222c3d530c 100644 (file)
@@ -292,7 +292,7 @@ MUTATOR_HOOKFUNCTION(trace, SV_StartFrame)
                it.debug_trace_button = btn;
                if (!btn || skip) continue;
                FOREACH_ENTITY(true, {
-                   it.solid_prev = it.solid;
+                       it.solid_prev = it.solid;
                        it.solid = SOLID_BBOX;
                });
                vector forward = '0 0 0'; vector right = '0 0 0'; vector up = '0 0 0';
@@ -300,8 +300,8 @@ MUTATOR_HOOKFUNCTION(trace, SV_StartFrame)
                vector pos = it.origin + it.view_ofs;
                traceline(pos, pos + forward * max_shot_distance, MOVE_NORMAL, it);
                FOREACH_ENTITY(true, {
-                   it.solid = it.solid_prev;
-            it.solid_prev = 0;
+                       it.solid = it.solid_prev;
+                       it.solid_prev = 0;
                });
                entity e = trace_ent;
                int i = etof(e);
index 6439a49bb21ce32c6c64bbc8814f37dbb8f5520d..3b534ab781d0f7d8a4614a4534fe4f208a28899d 100644 (file)
@@ -258,6 +258,6 @@ entity EFFECT_ROCKETMINSTA_LASER(int teamid)
         case NUM_TEAM_4:    e = EFFECT_ROCKETMINSTA_LASER_PINK; break;
         default:            e = EFFECT_ROCKETMINSTA_LASER_NEUTRAL; break;
     }
-    if (particleeffectnum(e) < 0 || Team_TeamToNumber(teamid) == -1) { e = EFFECT_TR_NEXUIZPLASMA; }
+    if (particleeffectnum(e) < 0 || !Team_IsValidTeam(teamid)) { e = EFFECT_TR_NEXUIZPLASMA; }
     return e;
 }
index 9a2d6af1d86f4efbfb300b774d22f0ed6b9dae06..bc048563e83e837df8cf5cc3301e35b9391085e3 100644 (file)
@@ -31,7 +31,8 @@ void assault_objective_use(entity this, entity actor, entity trigger)
 
 vector target_objective_spawn_evalfunc(entity this, entity player, entity spot, vector current)
 {
-       if(GetResourceAmount(this, RESOURCE_HEALTH) < 0 || GetResourceAmount(this, RESOURCE_HEALTH) >= ASSAULT_VALUE_INACTIVE)
+       float hlth = GetResourceAmount(this, RESOURCE_HEALTH);
+       if (hlth < 0 || hlth >= ASSAULT_VALUE_INACTIVE)
                return '-1 0 0';
        return current;
 }
@@ -61,16 +62,17 @@ void assault_objective_decrease_use(entity this, entity actor, entity trigger)
        else
                return; // already activated! cannot activate again!
 
-       if(GetResourceAmount(this.enemy, RESOURCE_HEALTH) < ASSAULT_VALUE_INACTIVE)
+       float hlth = GetResourceAmount(this.enemy, RESOURCE_HEALTH);
+       if (hlth < ASSAULT_VALUE_INACTIVE)
        {
-               if(GetResourceAmount(this.enemy, RESOURCE_HEALTH) - this.dmg > 0.5)
+               if (hlth - this.dmg > 0.5)
                {
                        GameRules_scoring_add_team(actor, SCORE, this.dmg);
                        TakeResource(this.enemy, RESOURCE_HEALTH, this.dmg);
                }
                else
                {
-                       GameRules_scoring_add_team(actor, SCORE, GetResourceAmount(this.enemy, RESOURCE_HEALTH));
+                       GameRules_scoring_add_team(actor, SCORE, hlth);
                        GameRules_scoring_add_team(actor, ASSAULT_OBJECTIVES, 1);
                        SetResourceAmountExplicit(this.enemy, RESOURCE_HEALTH, -1);
 
@@ -334,7 +336,8 @@ spawnfunc(target_objective_decrease)
 bool destructible_heal(entity targ, entity inflictor, float amount, float limit)
 {
        float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
-       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+       float hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       if (hlth <= 0 || hlth >= true_limit)
                return false;
 
        GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
@@ -411,7 +414,8 @@ void havocbot_goalrating_ast_targets(entity this, float ratingscale)
                entity destr = it;
                IL_EACH(g_assault_objectivedecreasers, it.targetname == destr.target,
                {
-                       if(GetResourceAmount(it.enemy, RESOURCE_HEALTH) > 0 && GetResourceAmount(it.enemy, RESOURCE_HEALTH) < ASSAULT_VALUE_INACTIVE)
+                       float hlth = GetResourceAmount(it.enemy, RESOURCE_HEALTH);
+                       if (hlth > 0 && hlth < ASSAULT_VALUE_INACTIVE)
                        {
                                found = true;
                                break;
@@ -426,9 +430,9 @@ void havocbot_goalrating_ast_targets(entity this, float ratingscale)
                // Find and rate waypoints around it
                found = false;
                entity best = NULL;
-               float bestvalue = 99999999999;
+               float bestvalue = FLOAT_MAX;
                entity des = it;
-               for(float radius = 0; radius < 1500 && !found; radius += 500)
+               for (float radius = 500; radius <= 1500 && !found; radius += 500)
                {
                        FOREACH_ENTITY_RADIUS(p, radius, it.classname == "waypoint" && !(it.wpflags & WAYPOINTFLAG_GENERATED),
                        {
@@ -489,10 +493,11 @@ void havocbot_role_ast_offense(entity this)
 
        if (navigation_goalrating_timeout(this))
        {
+               // role: offense
                navigation_goalrating_start(this);
-               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 650);
+               havocbot_goalrating_enemyplayers(this, 10000, this.origin, 650);
                havocbot_goalrating_ast_targets(this, 20000);
-               havocbot_goalrating_items(this, 15000, this.origin, 10000);
+               havocbot_goalrating_items(this, 30000, this.origin, 10000);
                navigation_goalrating_end(this);
 
                navigation_goalrating_timeout_set(this);
@@ -523,10 +528,11 @@ void havocbot_role_ast_defense(entity this)
 
        if (navigation_goalrating_timeout(this))
        {
+               // role: defense
                navigation_goalrating_start(this);
-               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 3000);
+               havocbot_goalrating_enemyplayers(this, 10000, this.origin, 3000);
                havocbot_goalrating_ast_targets(this, 20000);
-               havocbot_goalrating_items(this, 15000, this.origin, 10000);
+               havocbot_goalrating_items(this, 30000, this.origin, 10000);
                navigation_goalrating_end(this);
 
                navigation_goalrating_timeout_set(this);
@@ -539,12 +545,10 @@ void havocbot_role_ast_setrole(entity this, float role)
        {
                case HAVOCBOT_AST_ROLE_DEFENSE:
                        this.havocbot_role = havocbot_role_ast_defense;
-                       this.havocbot_role_flags = HAVOCBOT_AST_ROLE_DEFENSE;
                        this.havocbot_role_timeout = 0;
                        break;
                case HAVOCBOT_AST_ROLE_OFFENSE:
                        this.havocbot_role = havocbot_role_ast_offense;
-                       this.havocbot_role_flags = HAVOCBOT_AST_ROLE_OFFENSE;
                        this.havocbot_role_timeout = 0;
                        break;
        }
@@ -602,10 +606,10 @@ MUTATOR_HOOKFUNCTION(as, PlayHitsound)
        return (frag_victim.classname == "func_assault_destructible");
 }
 
-MUTATOR_HOOKFUNCTION(as, CheckAllowedTeams)
+MUTATOR_HOOKFUNCTION(as, TeamBalance_CheckAllowedTeams)
 {
        // assault always has 2 teams
-       c1 = c2 = 0;
+       M_ARGV(0, float) = BIT(0) | BIT(1);
        return true;
 }
 
index d949f18b34700775cd5ecc5429b78373a862c07b..ff65b66ed23923be629d0f6e16166370ff645080 100644 (file)
@@ -32,7 +32,6 @@ const int HAVOCBOT_AST_ROLE_NONE = 0;
 const int HAVOCBOT_AST_ROLE_DEFENSE = 2;
 const int HAVOCBOT_AST_ROLE_OFFENSE = 4;
 
-.int havocbot_role_flags;
 .float havocbot_attack_time;
 
 void(entity this) havocbot_role_ast_defense;
index f4aea4357ddfc3fecd65e3feabafda49890c72e1..a81a23a51cef6363a1b219a49206806fb096fc34 100644 (file)
@@ -7,53 +7,64 @@ bool autocvar_g_ca_spectate_enemies;
 
 void CA_count_alive_players()
 {
-       total_players = redalive = bluealive = yellowalive = pinkalive = 0;
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               switch(it.team)
+       total_players = 0;
+       for (int i = 1; i <= NUM_TEAMS; ++i)
+       {
+               Team_SetNumberOfAlivePlayers(Team_GetTeamFromIndex(i), 0);
+       }
+       FOREACH_CLIENT(IS_PLAYER(it) && Entity_HasValidTeam(it),
+       {
+               ++total_players;
+               if (IS_DEAD(it))
                {
-                       case NUM_TEAM_1: ++total_players; if(!IS_DEAD(it)) ++redalive; break;
-                       case NUM_TEAM_2: ++total_players; if(!IS_DEAD(it)) ++bluealive; break;
-                       case NUM_TEAM_3: ++total_players; if(!IS_DEAD(it)) ++yellowalive; break;
-                       case NUM_TEAM_4: ++total_players; if(!IS_DEAD(it)) ++pinkalive; break;
+                       continue;
                }
+               entity team_ = Entity_GetTeam(it);
+               int num_alive = Team_GetNumberOfAlivePlayers(team_);
+               ++num_alive;
+               Team_SetNumberOfAlivePlayers(team_, num_alive);
        });
-       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
-               STAT(REDALIVE, it) = redalive;
-               STAT(BLUEALIVE, it) = bluealive;
-               STAT(YELLOWALIVE, it) = yellowalive;
-               STAT(PINKALIVE, it) = pinkalive;
+       FOREACH_CLIENT(IS_REAL_CLIENT(it),
+       {
+               STAT(REDALIVE, it) = Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(
+                       1));
+               STAT(BLUEALIVE, it) = Team_GetNumberOfAlivePlayers(
+                       Team_GetTeamFromIndex(2));
+               STAT(YELLOWALIVE, it) = Team_GetNumberOfAlivePlayers(
+                       Team_GetTeamFromIndex(3));
+               STAT(PINKALIVE, it) = Team_GetNumberOfAlivePlayers(
+                       Team_GetTeamFromIndex(4));
        });
 }
 
-float CA_GetWinnerTeam()
+int CA_GetWinnerTeam()
 {
-       float winner_team = 0;
-       if(redalive >= 1)
-               winner_team = NUM_TEAM_1;
-       if(bluealive >= 1)
+       int winner_team = 0;
+       if (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(1)) >= 1)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_2;
+               winner_team = NUM_TEAM_1;
        }
-       if(yellowalive >= 1)
+       for (int i = 2; i <= NUM_TEAMS; ++i)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_3;
+               if (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) >= 1)
+               {
+                       if (winner_team != 0)
+                       {
+                               return 0;
+                       }
+                       winner_team = Team_IndexToTeam(i);
+               }
        }
-       if(pinkalive >= 1)
+       if (winner_team)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_4;
-       }
-       if(winner_team)
                return winner_team;
+       }
        return -1; // no player left
 }
 
 void nades_Clear(entity player);
 
-#define CA_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
-#define CA_ALIVE_TEAMS_OK() (CA_ALIVE_TEAMS() == NumTeams(ca_teams))
+#define CA_ALIVE_TEAMS_OK() (Team_GetNumberOfAliveTeams() == NumTeams(ca_teams))
 float CA_CheckWinner()
 {
        if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
@@ -69,8 +80,10 @@ float CA_CheckWinner()
        }
 
        CA_count_alive_players();
-       if(CA_ALIVE_TEAMS() > 1)
+       if (Team_GetNumberOfAliveTeams() > 1)
+       {
                return 0;
+       }
 
        int winner_team = CA_GetWinnerTeam();
        if(winner_team > 0)
@@ -119,14 +132,14 @@ bool CA_CheckTeams()
                return false;
        }
        int missing_teams_mask = 0;
-       if(ca_teams & BIT(0))
-               missing_teams_mask += (!redalive) * 1;
-       if(ca_teams & BIT(1))
-               missing_teams_mask += (!bluealive) * 2;
-       if(ca_teams & BIT(2))
-               missing_teams_mask += (!yellowalive) * 4;
-       if(ca_teams & BIT(3))
-               missing_teams_mask += (!pinkalive) * 8;
+       for (int i = 1; i <= NUM_TEAMS; ++i)
+       {
+               if ((ca_teams & Team_IndexToBit(i)) &&
+                       (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) == 0))
+               {
+                       missing_teams_mask |= Team_IndexToBit(i);
+               }
+       }
        if(prev_missing_teams_mask != missing_teams_mask)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
@@ -232,9 +245,10 @@ MUTATOR_HOOKFUNCTION(ca, reset_map_global)
        return true;
 }
 
-MUTATOR_HOOKFUNCTION(ca, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(ca, TeamBalance_CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
 {
        M_ARGV(0, float) = ca_teams;
+       return true;
 }
 
 entity ca_LastPlayerForTeam(entity this)
index 3f96b41142f162360dac01cf770a52b24391653f..131ade345d61e383ee51e260697d46c5d1c089f6 100644 (file)
@@ -449,7 +449,6 @@ void ctf_Handle_Throw(entity player, entity receiver, int droptype)
        flag.solid = SOLID_TRIGGER;
        flag.ctf_dropper = player;
        flag.ctf_droptime = time;
-       navigation_dynamicgoal_set(flag);
 
        flag.flags = FL_ITEM | FL_NOTARGET; // clear FL_ONGROUND for MOVETYPE_TOSS
 
@@ -488,6 +487,7 @@ void ctf_Handle_Throw(entity player, entity receiver, int droptype)
                        flag_velocity = (('0 0 1' * autocvar_g_ctf_throw_velocity_up) + ((v_forward * autocvar_g_ctf_throw_velocity_forward) * ((player.items & ITEM_Strength.m_itemid) ? autocvar_g_ctf_throw_strengthmultiplier : 1)));
                        flag.velocity = W_CalculateProjectileVelocity(player, player.velocity, flag_velocity, false);
                        ctf_Handle_Drop(flag, player, droptype);
+                       navigation_dynamicgoal_set(flag, player);
                        break;
                }
 
@@ -502,6 +502,7 @@ void ctf_Handle_Throw(entity player, entity receiver, int droptype)
                {
                        flag.velocity = W_CalculateProjectileVelocity(player, player.velocity, (('0 0 1' * autocvar_g_ctf_drop_velocity_up) + ((('0 1 0' * crandom()) + ('1 0 0' * crandom())) * autocvar_g_ctf_drop_velocity_side)), false);
                        ctf_Handle_Drop(flag, player, droptype);
+                       navigation_dynamicgoal_set(flag, player);
                        break;
                }
        }
@@ -1243,7 +1244,7 @@ void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag e
        flag.netname = strzone(sprintf("%s%s^7 flag", Team_ColorCode(teamnumber), Team_ColorName_Upper(teamnumber)));
        flag.team = teamnumber;
        flag.classname = "item_flag_team";
-       flag.target = "###item###"; // wut?
+       flag.target = "###item###"; // for finding the nearest item using findnearest
        flag.flags = FL_ITEM | FL_NOTARGET;
        IL_PUSH(g_items, flag);
        flag.solid = SOLID_TRIGGER;
@@ -1515,17 +1516,28 @@ void havocbot_goalrating_ctf_enemyflag(entity this, float ratingscale)
                head = head.ctf_worldflagnext;
        }
        if (head)
+       {
+               if (head.ctf_status == FLAG_CARRY)
+               {
+                       // adjust rating of our flag carrier depending on his health
+                       head = head.tag_entity;
+                       float f = bound(0, (head.health + head.armorvalue) / 100, 2) - 1;
+                       ratingscale += ratingscale * f * 0.1;
+               }
                navigation_routerating(this, head, ratingscale, 10000);
+       }
 }
 
 void havocbot_goalrating_ctf_enemybase(entity this, float ratingscale)
 {
+       // disabled because we always spawn waypoints for flags with waypoint_spawnforitem_force
+       /*
        if (!bot_waypoints_for_items)
        {
                havocbot_goalrating_ctf_enemyflag(this, ratingscale);
                return;
        }
-
+       */
        entity head;
 
        head = havocbot_ctf_find_enemy_flag(this);
@@ -1572,28 +1584,10 @@ void havocbot_goalrating_ctf_droppedflags(entity this, float ratingscale, vector
        }
 }
 
-void havocbot_goalrating_ctf_carrieritems(entity this, float ratingscale, vector org, float sradius)
-{
-       IL_EACH(g_items, it.bot_pickup,
-       {
-               // gather health and armor only
-               if (it.solid)
-               if (GetResourceAmount(it, RESOURCE_HEALTH) || GetResourceAmount(it, RESOURCE_ARMOR))
-               if (vdist(it.origin - org, <, sradius))
-               {
-                       // get the value of the item
-                       float t = it.bot_pickupevalfunc(this, it) * 0.0001;
-                       if (t > 0)
-                               navigation_routerating(this, it, t * ratingscale, 500);
-               }
-       });
-}
-
 void havocbot_ctf_reset_role(entity this)
 {
        float cdefense, cmiddle, coffense;
        entity mf, ef;
-       float c;
 
        if(IS_DEAD(this))
                return;
@@ -1622,15 +1616,30 @@ void havocbot_ctf_reset_role(entity this)
                return;
        }
 
-       // if there is only me on the team switch to offense
-       c = 0;
-       FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this), { ++c; });
+       // if there is no one else on the team switch to offense
+       int count = 0;
+       // don't check if this bot is a player since it isn't true when the bot is added to the server
+       FOREACH_CLIENT(it != this && IS_PLAYER(it) && SAME_TEAM(it, this), { ++count; });
 
-       if(c==1)
+       if (count == 0)
        {
                havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_OFFENSE);
                return;
        }
+       else if (time < CS(this).jointime + 1)
+       {
+               // if bots spawn all at once set good default roles
+               if (count == 1)
+               {
+                       havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_DEFENSE);
+                       return;
+               }
+               else if (count == 2)
+               {
+                       havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
+                       return;
+               }
+       }
 
        // Evaluate best position to take
        // Count mates on middle position
@@ -1648,6 +1657,25 @@ void havocbot_ctf_reset_role(entity this)
                havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_OFFENSE);
        else
                havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
+
+       // if bots spawn all at once assign them a more appropriated role after a while
+       if (time < CS(this).jointime + 1 && count > 2)
+               this.havocbot_role_timeout = time + 10 + random() * 10;
+}
+
+bool havocbot_ctf_is_basewaypoint(entity item)
+{
+       if (item.classname != "waypoint")
+               return false;
+
+       entity head = ctf_worldflaglist;
+       while (head)
+       {
+               if (item == head.bot_basewaypoint)
+                       return true;
+               head = head.ctf_worldflagnext;
+       }
+       return false;
 }
 
 void havocbot_role_ctf_carrier(entity this)
@@ -1668,30 +1696,30 @@ void havocbot_role_ctf_carrier(entity this)
        {
                navigation_goalrating_start(this);
 
+               // role: carrier
+               entity mf = havocbot_ctf_find_flag(this);
+               vector base_org = mf.dropped_origin;
+               float base_rating = (mf.ctf_status == FLAG_BASE) ? 10000 : (vdist(this.origin - base_org, >, 100) ? 2000 : 1000);
                if(ctf_oneflag)
-                       havocbot_goalrating_ctf_enemybase(this, 50000);
+                       havocbot_goalrating_ctf_enemybase(this, base_rating);
                else
-                       havocbot_goalrating_ctf_ourbase(this, 50000);
+                       havocbot_goalrating_ctf_ourbase(this, base_rating);
+
+               // start collecting items very close to the bot but only inside of own base radius
+               if (vdist(this.origin - base_org, <, havocbot_middlepoint_radius))
+                       havocbot_goalrating_items(this, 15000, this.origin, min(500, havocbot_middlepoint_radius * 0.5));
 
-               if(GetResourceAmount(this, RESOURCE_HEALTH) < 100)
-                       havocbot_goalrating_ctf_carrieritems(this, 1000, this.origin, 1000);
+               havocbot_goalrating_items(this, 10000, base_org, havocbot_middlepoint_radius * 0.5);
 
                navigation_goalrating_end(this);
 
                navigation_goalrating_timeout_set(this);
 
-               entity head = ctf_worldflaglist;
-               while (head)
-               {
-                       if (this.goalentity == head.bot_basewaypoint)
-                       {
-                               this.goalentity_lock_timeout = time + 5;
-                               break;
-                       }
-                       head = head.ctf_worldflagnext;
-               }
+               entity goal = this.goalentity;
+               if (havocbot_ctf_is_basewaypoint(goal) && vdist(goal.origin - this.origin, <, 100))
+                       this.goalentity_lock_timeout = time + ((this.bot_aimtarg) ? 2 : 3);
 
-               if (this.goalentity)
+               if (goal)
                        this.havocbot_cantfindflag = time + 10;
                else if (time > this.havocbot_cantfindflag)
                {
@@ -1727,11 +1755,15 @@ void havocbot_role_ctf_escort(entity this)
                this.havocbot_role_timeout = 0;
                return;
        }
+       if (ef.ctf_status == FLAG_DROPPED)
+       {
+               navigation_goalrating_timeout_expire(this, 1);
+               return;
+       }
 
        // If the flag carrier reached the base switch to defense
        mf = havocbot_ctf_find_flag(this);
-       if(mf.ctf_status!=FLAG_BASE)
-       if(vdist(ef.origin - mf.dropped_origin, <, 300))
+       if (mf.ctf_status != FLAG_BASE && vdist(ef.origin - mf.dropped_origin, <, 900))
        {
                havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_DEFENSE);
                return;
@@ -1756,9 +1788,10 @@ void havocbot_role_ctf_escort(entity this)
        {
                navigation_goalrating_start(this);
 
-               havocbot_goalrating_ctf_enemyflag(this, 30000);
-               havocbot_goalrating_ctf_ourstolenflag(this, 40000);
-               havocbot_goalrating_items(this, 10000, this.origin, 10000);
+               // role: escort
+               havocbot_goalrating_ctf_enemyflag(this, 10000);
+               havocbot_goalrating_ctf_ourstolenflag(this, 6000);
+               havocbot_goalrating_items(this, 21000, this.origin, 10000);
 
                navigation_goalrating_end(this);
 
@@ -1818,13 +1851,6 @@ void havocbot_role_ctf_offense(entity this)
                }
        }
 
-       // About to fail, switch to middlefield
-       if(GetResourceAmount(this, RESOURCE_HEALTH) < 50)
-       {
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
-               return;
-       }
-
        // Set the role timeout if necessary
        if (!this.havocbot_role_timeout)
                this.havocbot_role_timeout = time + 120;
@@ -1839,10 +1865,10 @@ void havocbot_role_ctf_offense(entity this)
        {
                navigation_goalrating_start(this);
 
-               havocbot_goalrating_ctf_ourstolenflag(this, 50000);
-               havocbot_goalrating_ctf_enemybase(this, 20000);
-               havocbot_goalrating_items(this, 5000, this.origin, 1000);
-               havocbot_goalrating_items(this, 1000, this.origin, 10000);
+               // role: offense
+               havocbot_goalrating_ctf_ourstolenflag(this, 10000);
+               havocbot_goalrating_ctf_enemybase(this, 10000);
+               havocbot_goalrating_items(this, 22000, this.origin, 10000);
 
                navigation_goalrating_end(this);
 
@@ -1888,15 +1914,20 @@ void havocbot_role_ctf_retriever(entity this)
 
        if (navigation_goalrating_timeout(this))
        {
-               float rt_radius;
-               rt_radius = 10000;
+               const float RT_RADIUS = 10000;
 
                navigation_goalrating_start(this);
 
-               havocbot_goalrating_ctf_ourstolenflag(this, 50000);
-               havocbot_goalrating_ctf_droppedflags(this, 40000, this.origin, rt_radius);
-               havocbot_goalrating_ctf_enemybase(this, 30000);
-               havocbot_goalrating_items(this, 500, this.origin, rt_radius);
+               // role: retriever
+               havocbot_goalrating_ctf_ourstolenflag(this, 10000);
+               havocbot_goalrating_ctf_droppedflags(this, 12000, this.origin, RT_RADIUS);
+               havocbot_goalrating_ctf_enemybase(this, 8000);
+               entity ef = havocbot_ctf_find_enemy_flag(this);
+               vector enemy_base_org = ef.dropped_origin;
+               // start collecting items very close to the bot but only inside of enemy base radius
+               if (vdist(this.origin - enemy_base_org, <, havocbot_middlepoint_radius))
+                       havocbot_goalrating_items(this, 27000, this.origin, min(500, havocbot_middlepoint_radius * 0.5));
+               havocbot_goalrating_items(this, 18000, this.origin, havocbot_middlepoint_radius);
 
                navigation_goalrating_end(this);
 
@@ -1945,15 +1976,20 @@ void havocbot_role_ctf_middle(entity this)
 
                navigation_goalrating_start(this);
 
-               havocbot_goalrating_ctf_ourstolenflag(this, 50000);
-               havocbot_goalrating_ctf_droppedflags(this, 30000, this.origin, 10000);
-               havocbot_goalrating_enemyplayers(this, 10000, org, havocbot_middlepoint_radius * 0.5);
-               havocbot_goalrating_items(this, 5000, org, havocbot_middlepoint_radius * 0.5);
-               havocbot_goalrating_items(this, 2500, this.origin, 10000);
-               havocbot_goalrating_ctf_enemybase(this, 2500);
+               // role: middle
+               havocbot_goalrating_ctf_ourstolenflag(this, 8000);
+               havocbot_goalrating_ctf_droppedflags(this, 9000, this.origin, 10000);
+               havocbot_goalrating_enemyplayers(this, 25000, org, havocbot_middlepoint_radius * 0.5);
+               havocbot_goalrating_items(this, 25000, org, havocbot_middlepoint_radius * 0.5);
+               havocbot_goalrating_items(this, 18000, this.origin, 10000);
+               havocbot_goalrating_ctf_enemybase(this, 3000);
 
                navigation_goalrating_end(this);
 
+               entity goal = this.goalentity;
+               if (havocbot_ctf_is_basewaypoint(goal) && vdist(goal.origin - this.origin, <, 100))
+                       this.goalentity_lock_timeout = time + 2;
+
                navigation_goalrating_timeout_set(this);
        }
 }
@@ -2008,17 +2044,18 @@ void havocbot_role_ctf_defense(entity this)
                        }
                });
 
+               // role: defense
                if(closestplayer)
                if(DIFF_TEAM(closestplayer, this))
                if(vdist(org - this.origin, >, 1000))
                if(checkpvs(this.origin,closestplayer)||random()<0.5)
-                       havocbot_goalrating_ctf_ourbase(this, 30000);
+                       havocbot_goalrating_ctf_ourbase(this, 10000);
 
-               havocbot_goalrating_ctf_ourstolenflag(this, 20000);
-               havocbot_goalrating_ctf_droppedflags(this, 20000, org, havocbot_middlepoint_radius);
-               havocbot_goalrating_enemyplayers(this, 15000, org, havocbot_middlepoint_radius);
-               havocbot_goalrating_items(this, 10000, org, havocbot_middlepoint_radius);
-               havocbot_goalrating_items(this, 5000, this.origin, 10000);
+               havocbot_goalrating_ctf_ourstolenflag(this, 5000);
+               havocbot_goalrating_ctf_droppedflags(this, 6000, org, havocbot_middlepoint_radius);
+               havocbot_goalrating_enemyplayers(this, 25000, org, havocbot_middlepoint_radius);
+               havocbot_goalrating_items(this, 25000, org, havocbot_middlepoint_radius);
+               havocbot_goalrating_items(this, 18000, this.origin, 10000);
 
                navigation_goalrating_end(this);
 
@@ -2466,11 +2503,9 @@ MUTATOR_HOOKFUNCTION(ctf, HavocBot_ChooseRole)
        return true;
 }
 
-MUTATOR_HOOKFUNCTION(ctf, CheckAllowedTeams)
+MUTATOR_HOOKFUNCTION(ctf, TeamBalance_CheckAllowedTeams)
 {
-       //M_ARGV(0, float) = ctf_teams;
        M_ARGV(1, string) = "ctf_team";
-       return true;
 }
 
 MUTATOR_HOOKFUNCTION(ctf, SpectateCopy)
@@ -2696,7 +2731,6 @@ spawnfunc(team_CTL_bluelolly)  { spawnfunc_item_flag_team2(this);    }
 // scoreboard setup
 void ctf_ScoreRules(int teams)
 {
-       CheckAllowedTeams(NULL);
        GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
         field_team(ST_CTF_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
         field(SP_CTF_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
index 24a82208cb30c80fc036b5960559906562e59c69..c7abb0e040b1ebeff253d90affc4e8f4d81602e0 100644 (file)
@@ -297,48 +297,56 @@ void dom_controlpoint_setup(entity this)
        WaypointSprite_SpawnFixed(WP_DomNeut, this.origin + '0 0 32', this, sprite, RADARICON_DOMPOINT);
 }
 
-float total_controlpoints;
+int total_control_points;
 void Domination_count_controlpoints()
 {
-       total_controlpoints = redowned = blueowned = yellowowned = pinkowned = 0;
+       total_control_points = 0;
+       for (int i = 1; i <= NUM_TEAMS; ++i)
+       {
+               Team_SetNumberOfControlPoints(Team_GetTeamFromIndex(i), 0);
+       }
        IL_EACH(g_dompoints, true,
        {
-               ++total_controlpoints;
-               redowned += (it.goalentity.team == NUM_TEAM_1);
-               blueowned += (it.goalentity.team == NUM_TEAM_2);
-               yellowowned += (it.goalentity.team == NUM_TEAM_3);
-               pinkowned += (it.goalentity.team == NUM_TEAM_4);
+               ++total_control_points;
+               if (!Entity_HasValidTeam(it.goalentity))
+               {
+                       continue;
+               }
+               entity team_ = Entity_GetTeam(it.goalentity);
+               int num_control_points = Team_GetNumberOfControlPoints(team_);
+               ++num_control_points;
+               Team_SetNumberOfControlPoints(team_, num_control_points);
        });
 }
 
-float Domination_GetWinnerTeam()
+int Domination_GetWinnerTeam()
 {
-       float winner_team = 0;
-       if(redowned == total_controlpoints)
-               winner_team = NUM_TEAM_1;
-       if(blueowned == total_controlpoints)
+       int winner_team = 0;
+       if (Team_GetNumberOfControlPoints(Team_GetTeamFromIndex(1)) ==
+               total_control_points)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_2;
+               winner_team = NUM_TEAM_1;
        }
-       if(yellowowned == total_controlpoints)
+       for (int i = 2; i <= NUM_TEAMS; ++i)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_3;
+               if (Team_GetNumberOfControlPoints(Team_GetTeamFromIndex(i)) ==
+                       total_control_points)
+               {
+                       if (winner_team != 0)
+                       {
+                               return 0;
+                       }
+                       winner_team = Team_IndexToTeam(i);
+               }
        }
-       if(pinkowned == total_controlpoints)
+       if (winner_team)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_4;
-       }
-       if(winner_team)
                return winner_team;
+       }
        return -1; // no control points left?
 }
 
-#define DOM_OWNED_CONTROLPOINTS() ((redowned > 0) + (blueowned > 0) + (yellowowned > 0) + (pinkowned > 0))
-#define DOM_OWNED_CONTROLPOINTS_OK() (DOM_OWNED_CONTROLPOINTS() < total_controlpoints)
-float Domination_CheckWinner()
+bool Domination_CheckWinner()
 {
        if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
        {
@@ -347,7 +355,7 @@ float Domination_CheckWinner()
 
                game_stopped = true;
                round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
-               return 1;
+               return true;
        }
 
        Domination_count_controlpoints();
@@ -355,7 +363,7 @@ float Domination_CheckWinner()
        float winner_team = Domination_GetWinnerTeam();
 
        if(winner_team == -1)
-               return 0;
+               return false;
 
        if(winner_team > 0)
        {
@@ -372,12 +380,12 @@ float Domination_CheckWinner()
        game_stopped = true;
        round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
 
-       return 1;
+       return true;
 }
 
-float Domination_CheckPlayers()
+bool Domination_CheckPlayers()
 {
-       return 1;
+       return true;
 }
 
 void Domination_RoundStart()
@@ -393,9 +401,9 @@ void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector or
                if(it.cnt > -1) // this is just being fought
                        navigation_routerating(this, it, ratingscale, 5000);
                else if(it.goalentity.cnt == 0) // unclaimed
-                       navigation_routerating(this, it, ratingscale * 0.5, 5000);
+                       navigation_routerating(this, it, ratingscale, 5000);
                else if(it.goalentity.team != this.team) // other team's point
-                       navigation_routerating(this, it, ratingscale * 0.2, 5000);
+                       navigation_routerating(this, it, ratingscale, 5000);
        });
 }
 
@@ -408,8 +416,8 @@ void havocbot_role_dom(entity this)
        {
                navigation_goalrating_start(this);
                havocbot_goalrating_controlpoints(this, 10000, this.origin, 15000);
-               havocbot_goalrating_items(this, 8000, this.origin, 8000);
-               //havocbot_goalrating_enemyplayers(this, 3000, this.origin, 2000);
+               havocbot_goalrating_items(this, 20000, this.origin, 8000);
+               //havocbot_goalrating_enemyplayers(this, 1500, this.origin, 2000);
                havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
                navigation_goalrating_end(this);
 
@@ -417,7 +425,7 @@ void havocbot_role_dom(entity this)
        }
 }
 
-MUTATOR_HOOKFUNCTION(dom, CheckAllowedTeams)
+MUTATOR_HOOKFUNCTION(dom, TeamBalance_CheckAllowedTeams)
 {
        // fallback?
        M_ARGV(0, float) = domination_teams;
@@ -428,12 +436,9 @@ MUTATOR_HOOKFUNCTION(dom, CheckAllowedTeams)
        {
                if(head.netname != "")
                {
-                       switch(head.team)
+                       if (Team_IsValidTeam(head.team))
                        {
-                               case NUM_TEAM_1: c1 = 0; break;
-                               case NUM_TEAM_2: c2 = 0; break;
-                               case NUM_TEAM_3: c3 = 0; break;
-                               case NUM_TEAM_4: c4 = 0; break;
+                               M_ARGV(0, float) |= Team_TeamToBit(head.team);
                        }
                }
 
@@ -584,10 +589,10 @@ void ScoreRules_dom(int teams)
 }
 
 // code from here on is just to support maps that don't have control point and team entities
-void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, Sound capsound, string capnarration, string capmessage)
+void dom_spawnteam(string teamname, float teamcolor, string pointmodel, float pointskin, Sound capsound, string capnarration, string capmessage)
 {
-    TC(Sound, capsound);
-    entity e = new_pure(dom_team);
+       TC(Sound, capsound);
+       entity e = new_pure(dom_team);
        e.netname = strzone(teamname);
        e.cnt = teamcolor;
        e.model = pointmodel;
@@ -621,7 +626,7 @@ void dom_spawnpoint(vector org)
 // spawn some default teams if the map is not set up for domination
 void dom_spawnteams(int teams)
 {
-    TC(int, teams);
+       TC(int, teams);
        dom_spawnteam(Team_ColoredFullName(NUM_TEAM_1), NUM_TEAM_1-1, "models/domination/dom_red.md3", 0, SND_DOM_CLAIM, "", "Red team has captured a control point");
        dom_spawnteam(Team_ColoredFullName(NUM_TEAM_2), NUM_TEAM_2-1, "models/domination/dom_blue.md3", 0, SND_DOM_CLAIM, "", "Blue team has captured a control point");
        if(teams >= 3)
@@ -644,14 +649,9 @@ void dom_DelayedInit(entity this) // Do this check with a delay so we can wait f
                dom_spawnteams(domination_teams);
        }
 
-       CheckAllowedTeams(NULL);
-       //domination_teams = ((c4>=0) ? 4 : (c3>=0) ? 3 : 2);
-
-       int teams = 0;
-       if(c1 >= 0) teams |= BIT(0);
-       if(c2 >= 0) teams |= BIT(1);
-       if(c3 >= 0) teams |= BIT(2);
-       if(c4 >= 0) teams |= BIT(3);
+       entity balance = TeamBalance_CheckAllowedTeams(NULL);
+       int teams = TeamBalance_GetAllowedTeams(balance);
+       TeamBalance_Destroy(balance);
        domination_teams = teams;
 
        domination_roundbased = autocvar_g_domination_roundbased;
index 1cdd4d1f84da90444aba85eb3521f195141b4f2f..152285410cc172b5b3fd0c9c75b3fa198af32e20 100644 (file)
@@ -2,6 +2,7 @@
 
 // TODO: sv_freezetag
 #ifdef SVQC
+
 #include <server/resources.qh>
 
 float autocvar_g_freezetag_frozen_maxtime;
@@ -13,29 +14,42 @@ float autocvar_g_freezetag_warmup;
 
 void freezetag_count_alive_players()
 {
-       total_players = redalive = bluealive = yellowalive = pinkalive = 0;
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               switch(it.team)
+       total_players = 0;
+       for (int i = 1; i <= NUM_TEAMS; ++i)
+       {
+               Team_SetNumberOfAlivePlayers(Team_GetTeamFromIndex(i), 0);
+       }
+       FOREACH_CLIENT(IS_PLAYER(it) && Entity_HasValidTeam(it),
+       {
+               ++total_players;
+               if ((GetResourceAmount(it, RESOURCE_HEALTH) < 1) ||
+                       (STAT(FROZEN, it) == 1))
                {
-                       case NUM_TEAM_1: ++total_players; if(GetResourceAmount(it, RESOURCE_HEALTH) >= 1 && STAT(FROZEN, it) != 1) ++redalive; break;
-                       case NUM_TEAM_2: ++total_players; if(GetResourceAmount(it, RESOURCE_HEALTH) >= 1 && STAT(FROZEN, it) != 1) ++bluealive; break;
-                       case NUM_TEAM_3: ++total_players; if(GetResourceAmount(it, RESOURCE_HEALTH) >= 1 && STAT(FROZEN, it) != 1) ++yellowalive; break;
-                       case NUM_TEAM_4: ++total_players; if(GetResourceAmount(it, RESOURCE_HEALTH) >= 1 && STAT(FROZEN, it) != 1) ++pinkalive; break;
+                       continue;
                }
+               entity team_ = Entity_GetTeam(it);
+               int num_alive = Team_GetNumberOfAlivePlayers(team_);
+               ++num_alive;
+               Team_SetNumberOfAlivePlayers(team_, num_alive);
        });
-       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
-               STAT(REDALIVE, it) = redalive;
-               STAT(BLUEALIVE, it) = bluealive;
-               STAT(YELLOWALIVE, it) = yellowalive;
-               STAT(PINKALIVE, it) = pinkalive;
+       FOREACH_CLIENT(IS_REAL_CLIENT(it),
+       {
+               STAT(REDALIVE, it) = Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(
+                       1));
+               STAT(BLUEALIVE, it) = Team_GetNumberOfAlivePlayers(
+                       Team_GetTeamFromIndex(2));
+               STAT(YELLOWALIVE, it) = Team_GetNumberOfAlivePlayers(
+                       Team_GetTeamFromIndex(3));
+               STAT(PINKALIVE, it) = Team_GetNumberOfAlivePlayers(
+                       Team_GetTeamFromIndex(4));
        });
 
        eliminatedPlayers.SendFlags |= 1;
 }
-#define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
-#define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == NumTeams(freezetag_teams))
 
-float freezetag_CheckTeams()
+#define FREEZETAG_ALIVE_TEAMS_OK() (Team_GetNumberOfAliveTeams() == NumTeams(freezetag_teams))
+
+bool freezetag_CheckTeams()
 {
        static float prev_missing_teams_mask;
        if(FREEZETAG_ALIVE_TEAMS_OK())
@@ -43,61 +57,61 @@ float freezetag_CheckTeams()
                if(prev_missing_teams_mask > 0)
                        Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
                prev_missing_teams_mask = -1;
-               return 1;
+               return true;
        }
        if(total_players == 0)
        {
                if(prev_missing_teams_mask > 0)
                        Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
                prev_missing_teams_mask = -1;
-               return 0;
+               return false;
        }
        int missing_teams_mask = 0;
-       if(freezetag_teams & BIT(0))
-               missing_teams_mask += (!redalive) * 1;
-       if(freezetag_teams & BIT(1))
-               missing_teams_mask += (!bluealive) * 2;
-       if(freezetag_teams & BIT(2))
-               missing_teams_mask += (!yellowalive) * 4;
-       if(freezetag_teams & BIT(3))
-               missing_teams_mask += (!pinkalive) * 8;
+       for (int i = 1; i <= NUM_TEAMS; ++i)
+       {
+               if ((freezetag_teams & Team_IndexToBit(i)) &&
+                       (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) == 0))
+               {
+                       missing_teams_mask |= Team_IndexToBit(i);
+               }
+       }
        if(prev_missing_teams_mask != missing_teams_mask)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
                prev_missing_teams_mask = missing_teams_mask;
        }
-       return 0;
+       return false;
 }
 
-float freezetag_getWinnerTeam()
+int freezetag_getWinnerTeam()
 {
-       float winner_team = 0;
-       if(redalive >= 1)
-               winner_team = NUM_TEAM_1;
-       if(bluealive >= 1)
+       int winner_team = 0;
+       if (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(1)) >= 1)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_2;
+               winner_team = NUM_TEAM_1;
        }
-       if(yellowalive >= 1)
+       for (int i = 2; i <= NUM_TEAMS; ++i)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_3;
+               if (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) >= 1)
+               {
+                       if (winner_team != 0)
+                       {
+                               return 0;
+                       }
+                       winner_team = Team_IndexToTeam(i);
+               }
        }
-       if(pinkalive >= 1)
+       if (winner_team)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_4;
-       }
-       if(winner_team)
                return winner_team;
+       }
        return -1; // no player left
 }
 
 void nades_Clear(entity);
 void nades_GiveBonus(entity player, float score);
 
-float freezetag_CheckWinner()
+bool freezetag_CheckWinner()
 {
        if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
        {
@@ -109,11 +123,13 @@ float freezetag_CheckWinner()
                });
                game_stopped = true;
                round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
-               return 1;
+               return true;
        }
 
-       if(FREEZETAG_ALIVE_TEAMS() > 1)
-               return 0;
+       if (Team_GetNumberOfAliveTeams() > 1)
+       {
+               return false;
+       }
 
        int winner_team = freezetag_getWinnerTeam();
        if(winner_team > 0)
@@ -135,20 +151,20 @@ float freezetag_CheckWinner()
 
        game_stopped = true;
        round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
-       return 1;
+       return true;
 }
 
 entity freezetag_LastPlayerForTeam(entity this)
 {
        entity last_pl = NULL;
-       FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
-               if(GetResourceAmount(it, RESOURCE_HEALTH) >= 1)
-               if(!STAT(FROZEN, it))
-               if(SAME_TEAM(it, this))
-               if(!last_pl)
-                       last_pl = it;
-               else
-                       return NULL;
+       FOREACH_CLIENT(IS_PLAYER(it) && it != this && SAME_TEAM(it, this), {
+               if (!STAT(FROZEN, it) && GetResourceAmount(it, RESOURCE_HEALTH) >= 1)
+               {
+                       if (!last_pl)
+                               last_pl = it;
+                       else
+                               return NULL;
+               }
        });
        return last_pl;
 }
@@ -182,6 +198,7 @@ void freezetag_Add_Score(entity targ, entity attacker)
        // else nothing - got frozen by the game type rules themselves
 }
 
+// to be called when the player is frozen by freezetag (on death, spectator join etc), gives the score
 void freezetag_Freeze(entity targ, entity attacker)
 {
        if(STAT(FROZEN, targ))
@@ -197,15 +214,7 @@ void freezetag_Freeze(entity targ, entity attacker)
        freezetag_Add_Score(targ, attacker);
 }
 
-void freezetag_Unfreeze(entity this)
-{
-       this.freezetag_frozen_time = 0;
-       this.freezetag_frozen_timeout = 0;
-
-       Unfreeze(this);
-}
-
-float freezetag_isEliminated(entity e)
+bool freezetag_isEliminated(entity e)
 {
        if(IS_PLAYER(e) && (STAT(FROZEN, e) == 1 || IS_DEAD(e)))
                return true;
@@ -220,9 +229,10 @@ float freezetag_isEliminated(entity e)
 void(entity this) havocbot_role_ft_freeing;
 void(entity this) havocbot_role_ft_offense;
 
-void havocbot_goalrating_freeplayers(entity this, float ratingscale, vector org, float sradius)
+void havocbot_goalrating_ft_freeplayers(entity this, float ratingscale, vector org, float sradius)
 {
-       float t;
+       entity best_pl = NULL;
+       float best_dist2 = FLOAT_MAX;
        FOREACH_CLIENT(IS_PLAYER(it) && it != this && SAME_TEAM(it, this), {
                if (STAT(FROZEN, it) == 1)
                {
@@ -230,14 +240,24 @@ void havocbot_goalrating_freeplayers(entity this, float ratingscale, vector org,
                                continue;
                        navigation_routerating(this, it, ratingscale, 2000);
                }
-               else if(vdist(it.origin - org, >, 400)) // avoid gathering all teammates in one place
+               else if (best_dist2
+                       && GetResourceAmount(it, RESOURCE_HEALTH) < GetResourceAmount(this, RESOURCE_HEALTH) + 30
+                       && vlen2(it.origin - org) < best_dist2)
                {
                        // If teamate is not frozen still seek them out as fight better
                        // in a group.
-                       t = 0.2 * 150 / (GetResourceAmount(this, RESOURCE_HEALTH) + GetResourceAmount(this, RESOURCE_ARMOR));
-                       navigation_routerating(this, it, t * ratingscale, 2000);
+                       best_dist2 = vlen2(it.origin - org);
+                       if (best_dist2 < 700 ** 2)
+                       {
+                               best_pl = NULL;
+                               best_dist2 = 0; // already close to a teammate
+                       }
+                       else
+                               best_pl = it;
                }
        });
+       if (best_pl)
+               navigation_routerating(this, best_pl, ratingscale / 2, 2000);
 }
 
 void havocbot_role_ft_offense(entity this)
@@ -250,10 +270,10 @@ void havocbot_role_ft_offense(entity this)
 
        // Count how many players on team are unfrozen.
        int unfrozen = 0;
-       FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this) && !(STAT(FROZEN, it) != 1), { unfrozen++; });
+       FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this) && !STAT(FROZEN, it), { unfrozen++; });
 
        // If only one left on team or if role has timed out then start trying to free players.
-       if (((unfrozen == 0) && (!STAT(FROZEN, this))) || (time > this.havocbot_role_timeout))
+       if ((unfrozen == 0 && !STAT(FROZEN, this)) || time > this.havocbot_role_timeout)
        {
                LOG_TRACE("changing role to freeing");
                this.havocbot_role = havocbot_role_ft_freeing;
@@ -264,9 +284,9 @@ void havocbot_role_ft_offense(entity this)
        if (navigation_goalrating_timeout(this))
        {
                navigation_goalrating_start(this);
-               havocbot_goalrating_items(this, 10000, this.origin, 10000);
-               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
-               havocbot_goalrating_freeplayers(this, 9000, this.origin, 10000);
+               havocbot_goalrating_items(this, 12000, this.origin, 10000);
+               havocbot_goalrating_enemyplayers(this, 10000, this.origin, 10000);
+               havocbot_goalrating_ft_freeplayers(this, 9000, this.origin, 10000);
                havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
                navigation_goalrating_end(this);
 
@@ -293,9 +313,9 @@ void havocbot_role_ft_freeing(entity this)
        if (navigation_goalrating_timeout(this))
        {
                navigation_goalrating_start(this);
-               havocbot_goalrating_items(this, 8000, this.origin, 10000);
-               havocbot_goalrating_enemyplayers(this, 10000, this.origin, 10000);
-               havocbot_goalrating_freeplayers(this, 20000, this.origin, 10000);
+               havocbot_goalrating_items(this, 10000, this.origin, 10000);
+               havocbot_goalrating_enemyplayers(this, 5000, this.origin, 10000);
+               havocbot_goalrating_ft_freeplayers(this, 20000, this.origin, 10000);
                havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
                navigation_goalrating_end(this);
 
@@ -313,7 +333,7 @@ void ft_RemovePlayer(entity this)
        SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0); // neccessary to update correctly alive stats
        if(!STAT(FROZEN, this))
                freezetag_LastPlayerForTeam_Notify(this);
-       freezetag_Unfreeze(this);
+       Unfreeze(this);
        freezetag_count_alive_players();
 }
 
@@ -342,7 +362,7 @@ MUTATOR_HOOKFUNCTION(ft, PlayerDies)
        if(round_handler_CountdownRunning())
        {
                if(STAT(FROZEN, frag_target))
-                       freezetag_Unfreeze(frag_target);
+                       Unfreeze(frag_target);
                freezetag_count_alive_players();
                return true; // let the player die so that he can respawn whenever he wants
        }
@@ -360,7 +380,7 @@ MUTATOR_HOOKFUNCTION(ft, PlayerDies)
                        freezetag_LastPlayerForTeam_Notify(frag_target);
                }
                else
-                       freezetag_Unfreeze(frag_target); // remove ice
+                       Unfreeze(frag_target); // remove ice
                SetResourceAmountExplicit(frag_target, RESOURCE_HEALTH, 0); // Unfreeze resets health
                frag_target.freezetag_frozen_timeout = -2; // freeze on respawn
                return true;
@@ -429,6 +449,15 @@ MUTATOR_HOOKFUNCTION(ft, GiveFragsForKill, CBC_ORDER_FIRST)
        return true;
 }
 
+MUTATOR_HOOKFUNCTION(ft, Unfreeze)
+{
+       entity targ = M_ARGV(0, entity);
+       targ.freezetag_frozen_time = 0;
+       targ.freezetag_frozen_timeout = 0;
+
+       freezetag_count_alive_players();
+}
+
 MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
 {
        if(game_stopped)
@@ -474,7 +503,7 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
 
                if(STAT(REVIVE_PROGRESS, player) >= 1)
                {
-                       freezetag_Unfreeze(player);
+                       Unfreeze(player);
                        freezetag_count_alive_players();
 
                        if(n == -1)
@@ -539,12 +568,17 @@ MUTATOR_HOOKFUNCTION(ft, HavocBot_ChooseRole)
                        bot.havocbot_role = havocbot_role_ft_offense;
        }
 
+       // if bots spawn all at once assign them a more appropriated role after a while
+       if (time < CS(bot).jointime + 1)
+               bot.havocbot_role_timeout = time + 10 + random() * 10;
+
        return true;
 }
 
-MUTATOR_HOOKFUNCTION(ft, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(ft, TeamBalance_CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
 {
        M_ARGV(0, float) = freezetag_teams;
+       return true;
 }
 
 MUTATOR_HOOKFUNCTION(ft, SetWeaponArena)
@@ -566,8 +600,8 @@ MUTATOR_HOOKFUNCTION(ft, FragCenterMessage)
                return; // target was already frozen, so this is just pushing them off the cliff
 
        Send_Notification(NOTIF_ONE, frag_attacker, MSG_CHOICE, CHOICE_FRAG_FREEZE, frag_target.netname, kill_count_to_attacker, (IS_BOT_CLIENT(frag_target) ? -1 : CS(frag_target).ping));
-       Send_Notification(NOTIF_ONE, frag_target, MSG_CHOICE, CHOICE_FRAGGED_FREEZE, frag_attacker.netname, kill_count_to_target, 
-                                                                               GetResourceAmount(frag_attacker, RESOURCE_HEALTH), GetResourceAmount(frag_attacker, RESOURCE_ARMOR), (IS_BOT_CLIENT(frag_attacker) ? -1 : CS(frag_attacker).ping));
+       Send_Notification(NOTIF_ONE, frag_target, MSG_CHOICE, CHOICE_FRAGGED_FREEZE, frag_attacker.netname, kill_count_to_target,
+               GetResourceAmount(frag_attacker, RESOURCE_HEALTH), GetResourceAmount(frag_attacker, RESOURCE_ARMOR), (IS_BOT_CLIENT(frag_attacker) ? -1 : CS(frag_attacker).ping));
 
        return true;
 }
@@ -580,7 +614,7 @@ void freezetag_Initialize()
 
        freezetag_teams = BITS(bound(2, freezetag_teams, 4));
        GameRules_scoring(freezetag_teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {
-           field(SP_FREEZETAG_REVIVALS, "revivals", 0);
+               field(SP_FREEZETAG_REVIVALS, "revivals", 0);
        });
 
        round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null);
index 3dff701959ef82c11f8f7e205daa3abfeb6af14b..00e2241c6866bf051135f891c3edb9433251b919 100644 (file)
@@ -548,9 +548,10 @@ MUTATOR_HOOKFUNCTION(inv, CheckRules_World)
        return true;
 }
 
-MUTATOR_HOOKFUNCTION(inv, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(inv, TeamBalance_CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
 {
        M_ARGV(0, float) = invasion_teams;
+       return true;
 }
 
 MUTATOR_HOOKFUNCTION(inv, AllowMobButcher)
@@ -561,7 +562,6 @@ MUTATOR_HOOKFUNCTION(inv, AllowMobButcher)
 
 void invasion_ScoreRules(int inv_teams)
 {
-       if(inv_teams) { CheckAllowedTeams(NULL); }
        GameRules_score_enabled(false);
        GameRules_scoring(inv_teams, 0, 0, {
            if (inv_teams) {
index c8bfbf25ae8513550434de0d0f21b0144afeb79e..1da7e81fbe3c97f77884cf27d06a86f878f094a3 100644 (file)
@@ -64,7 +64,7 @@ void ka_RespawnBall(entity this) // runs whenever the ball needs to be relocated
        settouch(this, ka_TouchEvent);
        setthink(this, ka_RespawnBall);
        this.nextthink = time + autocvar_g_keepawayball_respawntime;
-       navigation_dynamicgoal_set(this);
+       navigation_dynamicgoal_set(this, NULL);
 
        Send_Effect(EFFECT_ELECTRO_COMBO, oldballorigin, '0 0 0', 1);
        Send_Effect(EFFECT_ELECTRO_COMBO, this.origin, '0 0 0', 1);
@@ -89,8 +89,9 @@ void ka_TimeScoring(entity this)
 
 void ka_TouchEvent(entity this, entity toucher) // runs any time that the ball comes in contact with something
 {
-       if(game_stopped) return;
-       if(!this) return;
+       if (!this || game_stopped)
+               return;
+
        if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
        { // The ball fell off the map, respawn it since players can't get to it
                ka_RespawnBall(this);
@@ -146,6 +147,17 @@ void ka_TouchEvent(entity this, entity toucher) // runs any time that the ball c
        WaypointSprite_Kill(this.waypointsprite_attachedforcarrier);
 }
 
+void ka_PlayerReset(entity plyr)
+{
+       plyr.ballcarried = NULL;
+       GameRules_scoring_vip(plyr, false);
+       WaypointSprite_Kill(plyr.waypointsprite_attachedforcarrier);
+
+       // reset the player effects
+       plyr.glow_trail = false;
+       plyr.effects &= ~autocvar_g_keepaway_ballcarrier_effects;
+}
+
 void ka_DropEvent(entity plyr) // runs any time that a player is supposed to lose the ball
 {
        entity ball;
@@ -164,14 +176,8 @@ void ka_DropEvent(entity plyr) // runs any time that a player is supposed to los
        ball.effects &= ~EF_NODRAW;
        setorigin(ball, plyr.origin + '0 0 10');
        ball.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom();
-       entity e = ball.owner; ball.owner = NULL;
-       e.ballcarried = NULL;
-       GameRules_scoring_vip(e, false);
-       navigation_dynamicgoal_set(ball);
-
-       // reset the player effects
-       plyr.glow_trail = false;
-       plyr.effects &= ~autocvar_g_keepaway_ballcarrier_effects;
+       ball.owner = NULL;
+       navigation_dynamicgoal_set(ball, plyr);
 
        // messages and sounds
        ka_EventLog("dropped", plyr);
@@ -179,30 +185,72 @@ void ka_DropEvent(entity plyr) // runs any time that a player is supposed to los
        Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_KEEPAWAY_DROPPED, plyr.netname);
        sound(NULL, CH_TRIGGER, SND_KA_DROPPED, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
 
-       // scoring
-       // GameRules_scoring_add(plyr, KEEPAWAY_DROPS, 1); Not anymore, this is 100% the same as pickups and is useless.
-
        // waypoints
        WaypointSprite_Spawn(WP_KaBall, 0, 0, ball, '0 0 64', NULL, ball.team, ball, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER);
        WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
        WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier);
-       WaypointSprite_Kill(plyr.waypointsprite_attachedforcarrier);
+
+       ka_PlayerReset(plyr);
 }
 
-/** used to clear the ballcarrier whenever the match switches from warmup to normal */
-void ka_Reset(entity this)
+.bool pushable;
+
+MODEL(KA_BALL, "models/orbs/orbblue.md3");
+
+void ka_RemoveBall()
 {
-       if((this.owner) && (IS_PLAYER(this.owner)))
-               ka_DropEvent(this.owner);
+       entity plyr = ka_ball.owner;
+       if (plyr) // it was attached
+               ka_PlayerReset(plyr);
+       else
+               WaypointSprite_DetachCarrier(ka_ball);
+       delete(ka_ball);
+       ka_ball = NULL;
+}
+
+void ka_SpawnBall()
+{
+       entity e = new(keepawayball);
+       setmodel(e, MDL_KA_BALL);
+       setsize(e, '-16 -16 -20', '16 16 20'); // 20 20 20 was too big, player is only 16 16 24... gotta cheat with the Z (20) axis so that the particle isn't cut off
+       e.damageforcescale = autocvar_g_keepawayball_damageforcescale;
+       e.takedamage = DAMAGE_YES;
+       e.solid = SOLID_TRIGGER;
+       set_movetype(e, MOVETYPE_BOUNCE);
+       e.glow_color = autocvar_g_keepawayball_trail_color;
+       e.glow_trail = true;
+       e.flags = FL_ITEM;
+       IL_PUSH(g_items, e);
+       e.pushable = true;
+       settouch(e, ka_TouchEvent);
+       e.owner = NULL;
+       ka_ball = e;
+       navigation_dynamicgoal_init(ka_ball, false);
 
+       InitializeEntity(e, ka_RespawnBall, INITPRIO_SETLOCATION); // is this the right priority? Neh, I have no idea.. Well-- it works! So.
+}
+
+void ka_Handler_CheckBall(entity this)
+{
        if(time < game_starttime)
        {
-               setthink(this, ka_RespawnBall);
-               settouch(this, func_null);
-               this.nextthink = game_starttime;
+               if (ka_ball)
+                       ka_RemoveBall();
        }
        else
-               ka_RespawnBall(this);
+       {
+               if (!ka_ball)
+                       ka_SpawnBall();
+       }
+
+       this.nextthink = time;
+}
+
+void ka_Initialize() // run at the start of a match, initiates game mode
+{
+       ka_Handler = new(ka_Handler);
+       setthink(ka_Handler, ka_Handler_CheckBall);
+       ka_Handler.nextthink = time;
 }
 
 
@@ -212,20 +260,15 @@ void ka_Reset(entity this)
 
 void havocbot_goalrating_ball(entity this, float ratingscale, vector org)
 {
-       float t;
        entity ball_owner;
        ball_owner = ka_ball.owner;
 
        if (ball_owner == this)
                return;
 
-       // If ball is carried by player then hunt them down.
        if (ball_owner)
-       {
-               t = (GetResourceAmount(this, RESOURCE_HEALTH) + GetResourceAmount(this, RESOURCE_ARMOR)) / (GetResourceAmount(ball_owner, RESOURCE_HEALTH) + GetResourceAmount(ball_owner, RESOURCE_ARMOR));
-               navigation_routerating(this, ball_owner, t * ratingscale, 2000);
-       }
-       else // Ball has been dropped so collect.
+               navigation_routerating(this, ball_owner, ratingscale, 2000);
+       else
                navigation_routerating(this, ka_ball, ratingscale, 2000);
 }
 
@@ -238,7 +281,7 @@ void havocbot_role_ka_carrier(entity this)
        {
                navigation_goalrating_start(this);
                havocbot_goalrating_items(this, 10000, this.origin, 10000);
-               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
+               havocbot_goalrating_enemyplayers(this, 10000, this.origin, 10000);
                havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
                navigation_goalrating_end(this);
 
@@ -261,8 +304,8 @@ void havocbot_role_ka_collector(entity this)
        {
                navigation_goalrating_start(this);
                havocbot_goalrating_items(this, 10000, this.origin, 10000);
-               havocbot_goalrating_enemyplayers(this, 1000, this.origin, 10000);
-               havocbot_goalrating_ball(this, 20000, this.origin);
+               havocbot_goalrating_enemyplayers(this, 500, this.origin, 10000);
+               havocbot_goalrating_ball(this, 8000, this.origin);
                navigation_goalrating_end(this);
 
                navigation_goalrating_timeout_set(this);
@@ -437,39 +480,4 @@ MUTATOR_HOOKFUNCTION(ka, DropSpecialItems)
                ka_DropEvent(frag_target);
 }
 
-.bool pushable;
-
-// ==============
-// Initialization
-// ==============
-
-MODEL(KA_BALL, "models/orbs/orbblue.md3");
-
-void ka_SpawnBall() // loads various values for the ball, runs only once at start of match
-{
-       entity e = new(keepawayball);
-       setmodel(e, MDL_KA_BALL);
-       setsize(e, '-16 -16 -20', '16 16 20'); // 20 20 20 was too big, player is only 16 16 24... gotta cheat with the Z (20) axis so that the particle isn't cut off
-       e.damageforcescale = autocvar_g_keepawayball_damageforcescale;
-       e.takedamage = DAMAGE_YES;
-       e.solid = SOLID_TRIGGER;
-       set_movetype(e, MOVETYPE_BOUNCE);
-       e.glow_color = autocvar_g_keepawayball_trail_color;
-       e.glow_trail = true;
-       e.flags = FL_ITEM;
-       IL_PUSH(g_items, e);
-       e.pushable = true;
-       e.reset = ka_Reset;
-       settouch(e, ka_TouchEvent);
-       e.owner = NULL;
-       ka_ball = e;
-       navigation_dynamicgoal_init(ka_ball, false);
-
-       InitializeEntity(e, ka_RespawnBall, INITPRIO_SETLOCATION); // is this the right priority? Neh, I have no idea.. Well-- it works! So.
-}
-
-void ka_Initialize() // run at the start of a match, initiates game mode
-{
-       ka_SpawnBall();
-}
 #endif
index a4615c146843b779c3af2a4d54159f2d4d895655..8040ad6a5d0c3753c5a39ac27dbcc7d3b7d28163 100644 (file)
@@ -23,6 +23,7 @@ REGISTER_MUTATOR(ka, false)
 
 
 entity ka_ball;
+entity ka_Handler;
 
 void(entity this) havocbot_role_ka_carrier;
 void(entity this) havocbot_role_ka_collector;
index 6523612e2336220dadb86f03342aa8fc605980fc..5af4c45b7ddc9b7752f5aee5eb8a0c194efe08e5 100644 (file)
@@ -299,7 +299,7 @@ void kh_Key_Detach(entity key) // runs every time a key is dropped or lost. Runs
        key.takedamage = DAMAGE_YES;
        // let key.team stay
        key.modelindex = kh_key_dropped;
-       navigation_dynamicgoal_set(key);
+       navigation_dynamicgoal_set(key, key.owner);
        key.kh_previous_owner = key.owner;
        key.kh_previous_owner_playerid = key.owner.playerid;
 }
@@ -1077,9 +1077,9 @@ void havocbot_role_kh_carrier(entity this)
                navigation_goalrating_start(this);
 
                if(kh_Key_AllOwnedByWhichTeam() == this.team)
-                       havocbot_goalrating_kh(this, 10, 0.1, 0.1); // bring home
+                       havocbot_goalrating_kh(this, 10, 0.1, 0.05); // bring home
                else
-                       havocbot_goalrating_kh(this, 4, 4, 1); // play defensively
+                       havocbot_goalrating_kh(this, 4, 4, 0.5); // play defensively
 
                navigation_goalrating_end(this);
 
@@ -1117,11 +1117,11 @@ void havocbot_role_kh_defense(entity this)
 
                key_owner_team = kh_Key_AllOwnedByWhichTeam();
                if(key_owner_team == this.team)
-                       havocbot_goalrating_kh(this, 10, 0.1, 0.1); // defend key carriers
+                       havocbot_goalrating_kh(this, 10, 0.1, 0.05); // defend key carriers
                else if(key_owner_team == -1)
-                       havocbot_goalrating_kh(this, 4, 1, 0.1); // play defensively
+                       havocbot_goalrating_kh(this, 4, 1, 0.05); // play defensively
                else
-                       havocbot_goalrating_kh(this, 0.1, 0.1, 10); // ATTACK ANYWAY
+                       havocbot_goalrating_kh(this, 0.1, 0.1, 5); // ATTACK ANYWAY
 
                navigation_goalrating_end(this);
 
@@ -1160,11 +1160,11 @@ void havocbot_role_kh_offense(entity this)
 
                key_owner_team = kh_Key_AllOwnedByWhichTeam();
                if(key_owner_team == this.team)
-                       havocbot_goalrating_kh(this, 10, 0.1, 0.1); // defend anyway
+                       havocbot_goalrating_kh(this, 10, 0.1, 0.05); // defend anyway
                else if(key_owner_team == -1)
-                       havocbot_goalrating_kh(this, 0.1, 1, 4); // play offensively
+                       havocbot_goalrating_kh(this, 0.1, 1, 2); // play offensively
                else
-                       havocbot_goalrating_kh(this, 0.1, 0.1, 10); // ATTACK! EMERGENCY!
+                       havocbot_goalrating_kh(this, 0.1, 0.1, 5); // ATTACK! EMERGENCY!
 
                navigation_goalrating_end(this);
 
@@ -1209,11 +1209,11 @@ void havocbot_role_kh_freelancer(entity this)
 
                int key_owner_team = kh_Key_AllOwnedByWhichTeam();
                if(key_owner_team == this.team)
-                       havocbot_goalrating_kh(this, 10, 0.1, 0.1); // defend anyway
+                       havocbot_goalrating_kh(this, 10, 0.1, 0.05); // defend anyway
                else if(key_owner_team == -1)
-                       havocbot_goalrating_kh(this, 1, 10, 4); // prefer dropped keys
+                       havocbot_goalrating_kh(this, 1, 10, 2); // prefer dropped keys
                else
-                       havocbot_goalrating_kh(this, 0.1, 0.1, 10); // ATTACK ANYWAY
+                       havocbot_goalrating_kh(this, 0.1, 0.1, 5); // ATTACK ANYWAY
 
                navigation_goalrating_end(this);
 
@@ -1264,9 +1264,10 @@ MUTATOR_HOOKFUNCTION(kh, MatchEnd)
        kh_finalize();
 }
 
-MUTATOR_HOOKFUNCTION(kh, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(kh, TeamBalance_CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
 {
        M_ARGV(0, float) = kh_teams;
+       return true;
 }
 
 MUTATOR_HOOKFUNCTION(kh, SpectateCopy)
index 487012aa50902e7a834fdd708a7c0e45bb2928cc..89c53a82abc22eb1b7b4b8fc1a8784e8f5b6ea23 100644 (file)
@@ -635,7 +635,7 @@ void SpawnGoal(entity this)
 
        EXACTTRIGGER_INIT;
 
-       if(this.team != GOAL_OUT && Team_TeamToNumber(this.team) != -1)
+       if(this.team != GOAL_OUT && Team_IsValidTeam(this.team))
        {
                entity wp = WaypointSprite_SpawnFixed(WP_NbGoal, (this.absmin + this.absmax) * 0.5, this, sprite, RADARICON_NONE);
                wp.colormod = ((this.team) ? Team_ColorRGB(this.team) : '1 0.5 0');
@@ -920,7 +920,7 @@ MUTATOR_HOOKFUNCTION(nb, ItemTouch)
        return MUT_ITEMTOUCH_CONTINUE;
 }
 
-MUTATOR_HOOKFUNCTION(nb, CheckAllowedTeams)
+MUTATOR_HOOKFUNCTION(nb, TeamBalance_CheckAllowedTeams)
 {
        M_ARGV(1, string) = "nexball_team";
        return true;
index fd050df0a0f541cc0137303fe86ad15ab26ba60b..6d719eb977c512997131382e30a0698e0fcd14c0 100644 (file)
@@ -449,15 +449,17 @@ void ons_ControlPoint_Icon_Damage(entity this, entity inflictor, entity attacker
 
 bool ons_ControlPoint_Icon_Heal(entity targ, entity inflictor, float amount, float limit)
 {
+       float hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
        float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
-       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+       if (hlth <= 0 || hlth >= true_limit)
                return false;
 
        GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
        if(targ.owner.iscaptured)
-               WaypointSprite_UpdateHealth(targ.owner.sprite, GetResourceAmount(targ, RESOURCE_HEALTH));
+               WaypointSprite_UpdateHealth(targ.owner.sprite, hlth);
        else
-               WaypointSprite_UpdateBuildFinished(targ.owner.sprite, time + (targ.max_health - GetResourceAmount(targ, RESOURCE_HEALTH)) / (targ.count / ONS_CP_THINKRATE));
+               WaypointSprite_UpdateBuildFinished(targ.owner.sprite, time + (targ.max_health - hlth) / (targ.count / ONS_CP_THINKRATE));
        targ.SendFlags |= CPSF_STATUS;
        return true;
 }
@@ -904,13 +906,14 @@ void ons_GeneratorDamage(entity this, entity inflictor, entity attacker, float d
                }
        }
        TakeResource(this, RESOURCE_HEALTH, damage);
-       WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
+       float hlth = GetResourceAmount(this, RESOURCE_HEALTH);
+       WaypointSprite_UpdateHealth(this.sprite, hlth);
        // choose an animation frame based on health
-       this.frame = 10 * bound(0, (1 - GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health), 1);
+       this.frame = 10 * bound(0, (1 - hlth / this.max_health), 1);
        // see if the generator is still functional, or dying
-       if (GetResourceAmount(this, RESOURCE_HEALTH) > 0)
+       if (hlth > 0)
        {
-               this.lasthealth = GetResourceAmount(this, RESOURCE_HEALTH);
+               this.lasthealth = hlth;
        }
        else
        {
@@ -964,13 +967,15 @@ void ons_GeneratorDamage(entity this, entity inflictor, entity attacker, float d
 bool ons_GeneratorHeal(entity targ, entity inflictor, float amount, float limit)
 {
        float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
-       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+       float hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       if (hlth <= 0 || hlth >= true_limit)
                return false;
 
        GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
-       WaypointSprite_UpdateHealth(targ.sprite, GetResourceAmount(targ, RESOURCE_HEALTH));
-       targ.frame = 10 * bound(0, (1 - GetResourceAmount(targ, RESOURCE_HEALTH) / targ.max_health), 1);
-       targ.lasthealth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       WaypointSprite_UpdateHealth(targ.sprite, hlth);
+       targ.frame = 10 * bound(0, (1 - hlth / targ.max_health), 1);
+       targ.lasthealth = hlth;
        targ.SendFlags |= GSF_STATUS;
        return true;
 }
@@ -1108,46 +1113,52 @@ int total_generators;
 void Onslaught_count_generators()
 {
        entity e;
-       total_generators = redowned = blueowned = yellowowned = pinkowned = 0;
+       total_generators = 0;
+       for (int i = 1; i <= NUM_TEAMS; ++i)
+       {
+               Team_SetNumberOfControlPoints(Team_GetTeamFromIndex(i), 0);
+       }
        for(e = ons_worldgeneratorlist; e; e = e.ons_worldgeneratornext)
        {
                ++total_generators;
-               redowned += (e.team == NUM_TEAM_1 && GetResourceAmount(e, RESOURCE_HEALTH) > 0);
-               blueowned += (e.team == NUM_TEAM_2 && GetResourceAmount(e, RESOURCE_HEALTH) > 0);
-               yellowowned += (e.team == NUM_TEAM_3 && GetResourceAmount(e, RESOURCE_HEALTH) > 0);
-               pinkowned += (e.team == NUM_TEAM_4 && GetResourceAmount(e, RESOURCE_HEALTH) > 0);
+               if (GetResourceAmount(e, RESOURCE_HEALTH) < 1)
+               {
+                       continue;
+               }
+               entity team_ = Entity_GetTeam(e);
+               int num_control_points = Team_GetNumberOfControlPoints(team_);
+               ++num_control_points;
+               Team_SetNumberOfControlPoints(team_, num_control_points);
        }
 }
 
 int Onslaught_GetWinnerTeam()
 {
        int winner_team = 0;
-       if(redowned > 0)
-               winner_team = NUM_TEAM_1;
-       if(blueowned > 0)
+       if (Team_GetNumberOfControlPoints(Team_GetTeamFromIndex(1)) >= 1)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_2;
+               winner_team = NUM_TEAM_1;
        }
-       if(yellowowned > 0)
+       for (int i = 2; i <= NUM_TEAMS; ++i)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_3;
+               if (Team_GetNumberOfControlPoints(Team_GetTeamFromIndex(i)) >= 1)
+               {
+                       if (winner_team != 0)
+                       {
+                               return 0;
+                       }
+                       winner_team = Team_IndexToTeam(i);
+               }
        }
-       if(pinkowned > 0)
+       if (winner_team)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_4;
-       }
-       if(winner_team)
                return winner_team;
+       }
        return -1; // no generators left?
 }
 
 void nades_Clear(entity e);
 
-#define ONS_OWNED_GENERATORS() ((redowned > 0) + (blueowned > 0) + (yellowowned > 0) + (pinkowned > 0))
-#define ONS_OWNED_GENERATORS_OK() (ONS_OWNED_GENERATORS() > 1)
 bool Onslaught_CheckWinner()
 {
        if ((autocvar_timelimit && time > game_starttime + autocvar_timelimit * 60) || (round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0))
@@ -1193,8 +1204,10 @@ bool Onslaught_CheckWinner()
 
        Onslaught_count_generators();
 
-       if(ONS_OWNED_GENERATORS_OK())
+       if (Team_GetNumberOfTeamsWithControlPoints() > 1)
+       {
                return 0;
+       }
 
        int winner_team = Onslaught_GetWinnerTeam();
 
@@ -1251,71 +1264,26 @@ void Onslaught_RoundStart()
 
 // NOTE: LEGACY CODE, needs to be re-written!
 
-void havocbot_goalrating_ons_offenseitems(entity this, float ratingscale, vector org, float sradius)
-{
-       bool needarmor = false, needweapons = false;
-
-       // Needs armor/health?
-       if(GetResourceAmount(this, RESOURCE_HEALTH) < 100)
-               needarmor = true;
-
-       // Needs weapons?
-       int c = 0;
-       FOREACH(Weapons, it != WEP_Null, {
-               if(STAT(WEAPONS, this) & (it.m_wepset))
-               if(++c >= 4)
-                       break;
-       });
-
-       if(c<4)
-               needweapons = true;
-
-       if(!needweapons && !needarmor)
-               return;
-
-       LOG_DEBUG(this.netname, " needs weapons ", ftos(needweapons));
-       LOG_DEBUG(this.netname, " needs armor ", ftos(needarmor));
-
-       // See what is around
-       IL_EACH(g_items, it.bot_pickup,
-       {
-               // gather health and armor only
-               if (it.solid)
-               if ( ((GetResourceAmount(it, RESOURCE_HEALTH) || GetResourceAmount(it, RESOURCE_ARMOR)) && needarmor) || (STAT(WEAPONS, it) && needweapons ) )
-               if (vdist(it.origin - org, <, sradius))
-               {
-                       int t = it.bot_pickupevalfunc(this, it);
-                       if (t > 0)
-                               navigation_routerating(this, it, t * ratingscale, 500);
-               }
-       });
-}
-
 void havocbot_role_ons_setrole(entity this, int role)
 {
-       LOG_DEBUG(this.netname," switched to ");
        switch(role)
        {
                case HAVOCBOT_ONS_ROLE_DEFENSE:
-                       LOG_DEBUG("defense");
+                       LOG_DEBUG(this.netname, " switched to defense");
                        this.havocbot_role = havocbot_role_ons_defense;
-                       this.havocbot_role_flags = HAVOCBOT_ONS_ROLE_DEFENSE;
                        this.havocbot_role_timeout = 0;
                        break;
                case HAVOCBOT_ONS_ROLE_ASSISTANT:
-                       LOG_DEBUG("assistant");
+                       LOG_DEBUG(this.netname, " switched to assistant");
                        this.havocbot_role = havocbot_role_ons_assistant;
-                       this.havocbot_role_flags = HAVOCBOT_ONS_ROLE_ASSISTANT;
                        this.havocbot_role_timeout = 0;
                        break;
                case HAVOCBOT_ONS_ROLE_OFFENSE:
-                       LOG_DEBUG("offense");
+                       LOG_DEBUG(this.netname, " switched to offense");
                        this.havocbot_role = havocbot_role_ons_offense;
-                       this.havocbot_role_flags = HAVOCBOT_ONS_ROLE_OFFENSE;
                        this.havocbot_role_timeout = 0;
                        break;
        }
-       LOG_DEBUG("");
 }
 
 void havocbot_goalrating_ons_controlpoints_attack(entity this, float ratingscale)
@@ -1340,9 +1308,9 @@ void havocbot_goalrating_ons_controlpoints_attack(entity this, float ratingscale
 
                // Count team mates interested in this control point
                // (easier and cleaner than keeping counters per cp and teams)
-               FOREACH_CLIENT(IS_PLAYER(it), {
+               FOREACH_CLIENT(it != this && IS_PLAYER(it), {
                        if(SAME_TEAM(it, this))
-                       if(it.havocbot_role_flags & HAVOCBOT_ONS_ROLE_OFFENSE)
+                       if(it.havocbot_role == havocbot_role_ons_offense)
                        if(it.havocbot_ons_target == cp2)
                                ++c;
                });
@@ -1353,7 +1321,7 @@ void havocbot_goalrating_ons_controlpoints_attack(entity this, float ratingscale
        }
 
        // We'll consider only the best case
-       bestvalue = 99999999999;
+       bestvalue = FLOAT_MAX;
        cp = NULL;
        for(cp1 = ons_worldcplist; cp1; cp1 = cp1.ons_worldcpnext)
        {
@@ -1379,23 +1347,21 @@ void havocbot_goalrating_ons_controlpoints_attack(entity this, float ratingscale
                // Rate waypoints near it
                found = false;
                best = NULL;
-               bestvalue = 99999999999;
-               for(radius=0; radius<1000 && !found; radius+=500)
+               bestvalue = FLOAT_MAX;
+               for (radius = 500; radius <= 1000 && !found; radius += 500)
                {
-                       for(wp=findradius(cp.origin,radius); wp; wp=wp.chain)
+                       IL_EACH(g_waypoints, vdist(cp.origin - it.origin, <, radius),
                        {
-                               if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
-                               if(wp.classname=="waypoint")
-                               if(checkpvs(wp.origin,cp))
+                               if (!(it.wpflags & WAYPOINTFLAG_GENERATED) && checkpvs(it.origin, cp))
                                {
                                        found = true;
-                                       if(wp.cnt<bestvalue)
+                                       if (it.cnt < bestvalue)
                                        {
-                                               best = wp;
-                                               bestvalue = wp.cnt;
+                                               best = it;
+                                               bestvalue = it.cnt;
                                        }
                                }
-                       }
+                       });
                }
 
                if(best)
@@ -1418,22 +1384,7 @@ void havocbot_goalrating_ons_controlpoints_attack(entity this, float ratingscale
        {
                // Should be touched
                LOG_DEBUG(this.netname, " found a touchable controlpoint at ", vtos(cp.origin));
-               found = false;
-
-               // Look for auto generated waypoint
-               if (!bot_waypoints_for_items)
-               for (wp = findradius(cp.origin,100); wp; wp = wp.chain)
-               {
-                       if(wp.classname=="waypoint")
-                       {
-                               navigation_routerating(this, wp, ratingscale, 10000);
-                               found = true;
-                       }
-               }
-
-               // Nothing found, rate the controlpoint itself
-               if (!found)
-                       navigation_routerating(this, cp, ratingscale, 10000);
+               navigation_routerating(this, cp, ratingscale * 2, 10000);
        }
 }
 
@@ -1441,7 +1392,7 @@ bool havocbot_goalrating_ons_generator_attack(entity this, float ratingscale)
 {
        entity g, wp, bestwp;
        bool found;
-       int best;
+       int bestvalue;
 
        for(g = ons_worldgeneratorlist; g; g = g.ons_worldgeneratornext)
        {
@@ -1452,21 +1403,20 @@ bool havocbot_goalrating_ons_generator_attack(entity this, float ratingscale)
                // Rate waypoints near it
                found = false;
                bestwp = NULL;
-               best = 99999999999;
+               bestvalue = FLOAT_MAX;
 
-               for(wp=findradius(g.origin,400); wp; wp=wp.chain)
+               IL_EACH(g_waypoints, vdist(g.origin - it.origin, <, 400),
                {
-                       if(wp.classname=="waypoint")
-                       if(checkpvs(wp.origin,g))
+                       if (checkpvs(it.origin, g))
                        {
                                found = true;
-                               if(wp.cnt<best)
+                               if (it.cnt < bestvalue)
                                {
-                                       bestwp = wp;
-                                       best = wp.cnt;
+                                       bestwp = it;
+                                       bestvalue = it.cnt;
                                }
                        }
-               }
+               });
 
                if(bestwp)
                {
@@ -1519,9 +1469,9 @@ void havocbot_role_ons_offense(entity this)
        {
                navigation_goalrating_start(this);
                havocbot_goalrating_enemyplayers(this, 20000, this.origin, 650);
-               if(!havocbot_goalrating_ons_generator_attack(this, 20000))
-                       havocbot_goalrating_ons_controlpoints_attack(this, 20000);
-               havocbot_goalrating_ons_offenseitems(this, 10000, this.origin, 10000);
+               if(!havocbot_goalrating_ons_generator_attack(this, 10000))
+                       havocbot_goalrating_ons_controlpoints_attack(this, 10000);
+               havocbot_goalrating_items(this, 25000, this.origin, 10000);
                navigation_goalrating_end(this);
 
                navigation_goalrating_timeout_set(this);
@@ -1955,17 +1905,14 @@ MUTATOR_HOOKFUNCTION(ons, HavocBot_ChooseRole)
        return true;
 }
 
-MUTATOR_HOOKFUNCTION(ons, CheckAllowedTeams)
+MUTATOR_HOOKFUNCTION(ons, TeamBalance_CheckAllowedTeams)
 {
        // onslaught is special
        for(entity tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
        {
-               switch(tmp_entity.team)
+               if (Team_IsValidTeam(tmp_entity.team))
                {
-                       case NUM_TEAM_1: c1 = 0; break;
-                       case NUM_TEAM_2: c2 = 0; break;
-                       case NUM_TEAM_3: c3 = 0; break;
-                       case NUM_TEAM_4: c4 = 0; break;
+                       M_ARGV(0, float) |= Team_TeamToBit(tmp_entity.team);
                }
        }
 
@@ -2195,12 +2142,9 @@ spawnfunc(onslaught_generator)
 // scoreboard setup
 void ons_ScoreRules()
 {
-       CheckAllowedTeams(NULL);
-       int teams = 0;
-       if(c1 >= 0) teams |= BIT(0);
-       if(c2 >= 0) teams |= BIT(1);
-       if(c3 >= 0) teams |= BIT(2);
-       if(c4 >= 0) teams |= BIT(3);
+       entity balance = TeamBalance_CheckAllowedTeams(NULL);
+       int teams = TeamBalance_GetAllowedTeams(balance);
+       TeamBalance_Destroy(balance);
        GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
            field_team(ST_ONS_CAPS, "destroyed", SFL_SORT_PRIO_PRIMARY);
            field(SP_ONS_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
index 5c7fd469735b1e38cad2abdf8e11165d9ffb3d66..7a9b192a5a7b041e313c807dd464b04d3e0c3e98 100644 (file)
@@ -80,7 +80,6 @@ const int HAVOCBOT_ONS_ROLE_OFFENSE   = 8;
 
 .entity havocbot_ons_target;
 
-.int havocbot_role_flags;
 .float havocbot_attack_time;
 
 void havocbot_role_ons_defense(entity this);
index c98e1b6a898ce0a309e69d079b5a43a0a84f883f..aaf83cb39bc9af705a4111bff581efed9b6dc5f6 100644 (file)
@@ -366,9 +366,10 @@ MUTATOR_HOOKFUNCTION(rc, ForbidPlayerScore_Clear)
                return true; // in qualifying, you don't lose score by observing
 }
 
-MUTATOR_HOOKFUNCTION(rc, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(rc, TeamBalance_CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
 {
        M_ARGV(0, float) = race_teams;
+       return true;
 }
 
 MUTATOR_HOOKFUNCTION(rc, Scores_CountFragsRemaining)
index 39e5fec1e19cd62fd7783252c3c5d81ea97ba89c..cf328902bf3aa866fef2bfad25846b5adf672605 100644 (file)
@@ -53,10 +53,9 @@ void tdm_DelayedInit(entity this)
        }
 }
 
-MUTATOR_HOOKFUNCTION(tdm, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(tdm, TeamBalance_CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
 {
        M_ARGV(1, string) = "tdm_team";
-       return true;
 }
 
 MUTATOR_HOOKFUNCTION(tdm, Scores_CountFragsRemaining)
index 979477cbafab6c676c4fdc7cabfeedf43134725b..ca1b6f8e74649e80c2b1ebe8c180871c00cef75e 100644 (file)
@@ -2,7 +2,6 @@
 
 // TODO: find a better location for these?
 float total_players;
-float redalive, bluealive, yellowalive, pinkalive;
 
 // todo: accept the number of teams as a parameter
 void GameRules_teams(bool value);
index 3109e7c92f93c66adc8c0f5d274bef901bf019e3..030b4db1c089f53f06c62a1cb19590ac48b50977 100644 (file)
@@ -51,16 +51,26 @@ const int IT_PICKUPMASK                     = IT_UNLIMITED_AMMO | IT_JETPACK | IT_FU
 .float  strength_finished = _STAT(STRENGTH_FINISHED);
 .float  invincible_finished = _STAT(INVINCIBLE_FINISHED);
 
+#define spawnfunc_body(item) \
+       if (!Item_IsDefinitionAllowed(item)) \
+       { \
+               startitem_failed = true; \
+               delete(this); \
+               return; \
+       } \
+       StartItem(this, item)
+
 #define SPAWNFUNC_ITEM(name, item) \
-    spawnfunc(name) \
+       spawnfunc(name) \
+       { \
+               spawnfunc_body(item); \
+       }
+
+#define SPAWNFUNC_ITEM_COND(name, cond, item1, item2) \
+       spawnfunc(name) \
        { \
-               if (!Item_IsDefinitionAllowed(item)) \
-               { \
-                       startitem_failed = true; \
-                       delete(this); \
-                       return; \
-               } \
-               StartItem(this, item); \
+               entity item = (cond) ? item1 : item2; \
+               spawnfunc_body(item); \
        }
 
 #else
@@ -73,7 +83,7 @@ enum
 {
        ITEM_FLAG_NORMAL = BIT(0), ///< Item is usable during normal gameplay.
        ITEM_FLAG_MUTATORBLOCKED = BIT(1),
-    ITEM_FLAG_RESOURCE = BIT(2) ///< Item is is a resource, not a held item.
+       ITEM_FLAG_RESOURCE = BIT(2) ///< Item is is a resource, not a held item.
 };
 
 #define ITEM_HANDLE(signal, ...) __Item_Send_##signal(__VA_ARGS__)
index 1c10afa488a581065888af5fa7a7324e82ca2eb6..9de1235361787678286474044f004ddbc8e4c31c 100644 (file)
@@ -10,7 +10,7 @@ CLASS(Powerup, Pickup)
 #ifdef SVQC
     ATTRIB(Powerup, m_mins, vector, '-16 -16 0');
     ATTRIB(Powerup, m_maxs, vector, '16 16 80');
-    ATTRIB(Powerup, m_botvalue, int, 20000);
+    ATTRIB(Powerup, m_botvalue, int, 11000);
     ATTRIB(Powerup, m_itemflags, int, FL_POWERUP);
     ATTRIB(Powerup, m_respawntime, float(), GET(g_pickup_respawntime_powerup));
     ATTRIB(Powerup, m_respawntimejitter, float(), GET(g_pickup_respawntimejitter_powerup));
index 50170e251b5fb8cb518fe24e7fe1fbd22b08f34a..45346dc8ea70440affb817baa6e4ddd8e5888f5e 100644 (file)
@@ -9,7 +9,7 @@ classfield(Wall) .float loddistance1, loddistance2;
 classfield(Wall) .vector saved;
 
 // Needed for interactive clientwalls
-.float inactive; // Clientwall disappears when inactive
+.bool inactive; // Clientwall disappears when inactive
 .float alpha_max, alpha_min;
 // If fade_start > fade_end, fadeout will be inverted
 // fade_vertical_offset is a vertival offset for player position
index cd6adec310ccf2c00b974f92329f519f0561b45e..268134e806757aa4f459295ad818bb4a8db013bc 100644 (file)
@@ -8,7 +8,7 @@ IntrusiveList g_jumppads;
 STATIC_INIT(g_jumppads) { g_jumppads = IL_NEW(); }
 
 .float pushltime;
-.float istypefrag;
+.bool istypefrag;
 .float height;
 
 const int NUM_JUMPPADSUSED = 3;
index 37d82e22ef72d9f1579d4056349bcf39f61d012a..3174fa7ff31ee4006231c4f45fbba5395619fe74 100644 (file)
@@ -2,12 +2,20 @@
 
 #ifdef SVQC
 
+.float m_chainsaw_damage; // accumulated damage of the missile as it passes trough enemies
+
 void W_OverkillRocketPropelledChainsaw_Explode(entity this, entity directhitentity)
 {
        this.event_damage = func_null;
        this.takedamage = DAMAGE_NO;
 
-       RadiusDamage(this, this.realowner, WEP_CVAR_PRI(okrpc, damage), WEP_CVAR_PRI(okrpc, edgedamage), WEP_CVAR_PRI(okrpc, radius), NULL, NULL, WEP_CVAR_PRI(okrpc, force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
+       float explosion_damage = RadiusDamage(this, this.realowner, WEP_CVAR_PRI(okrpc, damage), WEP_CVAR_PRI(okrpc, edgedamage), WEP_CVAR_PRI(okrpc, radius), NULL, NULL, WEP_CVAR_PRI(okrpc, force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
+       if (explosion_damage > 0 && this.m_chainsaw_damage > 0)
+       {
+               // if chainsaw hit something, it removed fired damage (so that direct hit is 100%)
+               // now that we also damaged something by explosion we'd go over 100% so let's add the fired damage back
+               accuracy_add(this.realowner, DEATH_WEAPONOF(this.projectiledeathtype).m_id, WEP_CVAR(okrpc, damage), 0);
+       }
 
        delete(this);
 }
@@ -53,8 +61,22 @@ void W_OverkillRocketPropelledChainsaw_Think(entity this)
        vector mydir = normalize(this.velocity);
 
        tracebox(this.origin, this.mins, this.maxs, this.origin + mydir * (2 * myspeed_accel), MOVE_NORMAL, this);
-       if(IS_PLAYER(trace_ent))
+       if (IS_PLAYER(trace_ent))
+       {
+               if (accuracy_isgooddamage(this.realowner, trace_ent))
+               {
+                       if (this.m_chainsaw_damage == 0) // first hit
+                       {
+                               // The fired damage of the explosion is already counted in the statistics (when launching the chainsaw).
+                               // We remove it here so that a direct hit that passes through and doesn't damage anything by the explosion later is still 100%.
+                               float fired_damage = WEP_CVAR_PRI(okrpc, damage2) - WEP_CVAR_PRI(okrpc, damage);
+                               float hit_damage = WEP_CVAR_PRI(okrpc, damage2);
+                               accuracy_add(this.realowner, DEATH_WEAPONOF(this.projectiledeathtype).m_id, fired_damage, hit_damage);
+                       }
+                       this.m_chainsaw_damage += WEP_CVAR_PRI(okrpc, damage2);
+               }
                Damage(trace_ent, this, this.realowner, WEP_CVAR_PRI(okrpc, damage2), this.projectiledeathtype, this.weaponentity_fld, this.origin, normalize(this.origin - trace_ent.origin) * WEP_CVAR_PRI(okrpc, force));
+       }
 
        this.velocity = mydir * (myspeed + (WEP_CVAR_PRI(okrpc, speedaccel) * sys_frametime));
 
@@ -106,6 +128,7 @@ void W_OverkillRocketPropelledChainsaw_Attack (Weapon thiswep, entity actor, .en
        SUB_SetFade (flash, time, 0.1);
        flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
        W_AttachToShotorg(actor, weaponentity, flash, '5 0 0');
+       missile.m_chainsaw_damage = 0;
 
        MUTATOR_CALLHOOK(EditProjectile, actor, missile);
 }
index d80b21d5a6e0cec3b4a59f5c403b948eece5cd85..9458189fd0ed20a448b9da906b3f654c12632452 100644 (file)
@@ -312,8 +312,9 @@ string sandbox_ObjectPort_Save(entity e, bool database)
 entity sandbox_ObjectPort_Load(entity this, string s, float database)
 {
        // load object properties, and spawn a new object with them
-       float n, i;
+       int n, i;
        entity e = NULL, parent = NULL;
+       string arg = string_null;
 
        // separate objects between the ; symbols
        n = tokenizebyseparator(s, "; ");
@@ -323,9 +324,10 @@ entity sandbox_ObjectPort_Load(entity this, string s, float database)
        // now separate and apply the properties of each object
        for(i = 0; i < n; ++i)
        {
-               float argv_num;
+               #define SANDBOX_GETARG arg = argv(++argv_num);
+               int argv_num = -1; // starts at -1 so I don't need postincrement
+
                string tagname = string_null;
-               argv_num = 0;
                tokenize_console(port_string[i]);
                e = sandbox_ObjectSpawn(this, database);
 
@@ -333,38 +335,40 @@ entity sandbox_ObjectPort_Load(entity this, string s, float database)
                if(i)
                {
                        // properties stored only for child objects
-                       if(argv(argv_num) != "")        tagname = argv(argv_num);       else tagname = string_null;     ++argv_num;
+                       SANDBOX_GETARG; tagname = (arg != "") ? arg : string_null;
                }
                else
                {
                        // properties stored only for parent objects
                        if(database)
                        {
-                               setorigin(e, stov(argv(argv_num)));     ++argv_num;
-                               e.angles = stov(argv(argv_num));        ++argv_num;
+                               SANDBOX_GETARG; setorigin(e, stov(arg));
+                               SANDBOX_GETARG; e.angles = stov(arg);
                        }
                        parent = e; // mark parent objects as such
                }
                // properties stored for all objects
-               _setmodel(e, argv(argv_num));   ++argv_num;
-               e.skin = stof(argv(argv_num));  ++argv_num;
-               e.alpha = stof(argv(argv_num)); ++argv_num;
-               e.colormod = stov(argv(argv_num));      ++argv_num;
-               e.glowmod = stov(argv(argv_num));       ++argv_num;
-               e.frame = stof(argv(argv_num)); ++argv_num;
-               sandbox_ObjectEdit_Scale(e, stof(argv(argv_num)));      ++argv_num;
-               e.solid = e.old_solid = stof(argv(argv_num));   ++argv_num;
-               e.old_movetype = stof(argv(argv_num));  ++argv_num;
+               SANDBOX_GETARG; _setmodel(e, arg);
+               SANDBOX_GETARG; e.skin = stof(arg);
+               SANDBOX_GETARG; e.alpha = stof(arg);
+               SANDBOX_GETARG; e.colormod = stov(arg);
+               SANDBOX_GETARG; e.glowmod = stov(arg);
+               SANDBOX_GETARG; e.frame = stof(arg);
+               SANDBOX_GETARG; sandbox_ObjectEdit_Scale(e, stof(arg));
+               SANDBOX_GETARG; e.solid = e.old_solid = stof(arg);
+               SANDBOX_GETARG; e.old_movetype = stof(arg);
                set_movetype(e, e.old_movetype);
-               e.damageforcescale = stof(argv(argv_num));      ++argv_num;
-               strfree(e.material);    if(argv(argv_num) != "")        e.material = strzone(argv(argv_num));   else    e.material = string_null;       ++argv_num;
+               SANDBOX_GETARG; e.damageforcescale = stof(arg);
+               strfree(e.material);
+               SANDBOX_GETARG; e.material = (arg != "") ? strzone(arg) : string_null;
                if(database)
                {
                        // properties stored only for the database
-                       strfree(e.crypto_idfp); if(argv(argv_num) != "")        e.crypto_idfp = strzone(argv(argv_num));        else    e.crypto_idfp = string_null;    ++argv_num;
-                       strcpy(e.netname, argv(argv_num));      ++argv_num;
-                       strcpy(e.message, argv(argv_num));      ++argv_num;
-                       strcpy(e.message2, argv(argv_num));     ++argv_num;
+                       strfree(e.crypto_idfp);
+                       SANDBOX_GETARG; e.crypto_idfp = (arg != "") ? strzone(arg) : string_null;
+                       SANDBOX_GETARG; strcpy(e.netname, arg);
+                       SANDBOX_GETARG; strcpy(e.message, arg);
+                       SANDBOX_GETARG; strcpy(e.message2, arg);
                }
 
                // attach last
index 115e6ca9109341fcaa4c61974eaafe416b342f15..e74cfb1152844c485c94e9f72705d7d004f46e54 100644 (file)
@@ -28,7 +28,9 @@ MUTATOR_HOOKFUNCTION(vh, GrappleHookThink)
                thehook.owner.damage_dealt += autocvar_g_vampirehook_damage;
                Damage(dmgent, thehook, thehook.owner, autocvar_g_vampirehook_damage, WEP_HOOK.m_id, DMG_NOWEP, thehook.origin, '0 0 0');
                entity targ = ((SAME_TEAM(thehook.owner, thehook.aiment)) ? thehook.aiment : thehook.owner);
-               Heal(targ, thehook.owner, autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
+               // TODO: we can't do this due to an issue with globals and the mutator arguments
+               //Heal(targ, thehook.owner, autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
+               SetResourceAmountExplicit(targ, RESOURCE_HEALTH, min(GetResourceAmount(targ, RESOURCE_HEALTH) + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max));
 
                if(dmgent == thehook.owner)
                        TakeResource(dmgent, RESOURCE_HEALTH, autocvar_g_vampirehook_damage); // FIXME: friendly fire?!
index b527bdc1a84b020088603478e4007db063ce5c75..c8c4db546a71267d4bb86f7e71e0239ba1c7f629 100644 (file)
@@ -14,8 +14,8 @@ REGISTER_WAYPOINT(RaceFinish, _("Finish"), "", '1 0.5 0', 1);
 REGISTER_WAYPOINT(RaceStart, _("Start"), "", '1 0.5 0', 1);
 REGISTER_WAYPOINT(RaceStartFinish, _("Start"), "", '1 0.5 0', 1);
 
-REGISTER_WAYPOINT(AssaultDefend, _("Defend"), "", '1 0.5 0', 1);
-REGISTER_WAYPOINT(AssaultDestroy, _("Destroy"), "", '1 0.5 0', 1);
+REGISTER_WAYPOINT(AssaultDefend, _("Defend"), "as_defend", '1 0.5 0', 1);
+REGISTER_WAYPOINT(AssaultDestroy, _("Destroy"), "as_destroy", '1 0.5 0', 1);
 REGISTER_WAYPOINT(AssaultPush, _("Push"), "", '1 0.5 0', 1);
 
 REGISTER_WAYPOINT(FlagCarrier, _("Flag carrier"), "", '0.8 0.8 0', 1);
index dcbb65f65cd29472659141b93617b7a8182c2075..66904d0070bd879fd151e14be11df995600a3e43 100644 (file)
@@ -552,11 +552,13 @@ void Draw_WaypointSprite(entity this)
         LOG_INFOF("WARNING: sprite of name %s has no color, using pink so you notice it", spriteimage);
     }
 
-    if (time - floor(time) > 0.5)
+    float health_val = GetResourceAmount(this, RESOURCE_HEALTH);
+    float blink_time = (health_val >= 0) ? (health_val * 10) : time;
+    if (blink_time - floor(blink_time) > 0.5)
     {
         if (this.helpme && time < this.helpme)
             a *= SPRITE_HELPME_BLINK;
-        else if (this.lifetime > 0) // fading out waypoints don't blink
+        else if (!this.lifetime) // fading out waypoints don't blink
             a *= spritelookupblinkvalue(this, spriteimage);
     }
 
@@ -590,7 +592,7 @@ void Draw_WaypointSprite(entity this)
             ang += M_PI;
 
                float f1 = d.x / vid_conwidth;
-               float f2 = d.y / vid_conheight; 
+               float f2 = d.y / vid_conheight;
                if (f1 == 0) { f1 = 0.000001; }
                if (f2 == 0) { f2 = 0.000001; }
 
@@ -1101,7 +1103,7 @@ entity WaypointSprite_SpawnFixed(
 
 entity WaypointSprite_DeployFixed(
     entity spr,
-    float limited_range,
+    bool limited_range,
     entity player,
     vector ofs,
     entity icon // initial icon
@@ -1133,7 +1135,7 @@ entity WaypointSprite_DeployPersonal(
 entity WaypointSprite_Attach(
     entity spr,
     entity player,
-    float limited_range,
+    bool limited_range,
     entity icon // initial icon
 )
 {
index 94d735a1f6096b2f3a77a0b712e4124912bb0aa3..9bfa4862befc03fb6e9a7f8d9184787922b89e7c 100644 (file)
@@ -203,7 +203,7 @@ entity WaypointSprite_SpawnFixed(
 .entity waypointsprite_deployed_fixed;
 entity WaypointSprite_DeployFixed(
     entity spr,
-    float limited_range,
+    bool limited_range,
     entity player,
     vector ofs,
     entity icon // initial icon
@@ -222,7 +222,7 @@ entity WaypointSprite_DeployPersonal(
 entity WaypointSprite_Attach(
     entity spr,
     entity player,
-    float limited_range,
+    bool limited_range,
     entity icon // initial icon
 );
 
index a15ef80d1e7f8feece7b0dc8f7927e3962d50db0..db0e0503f08b75b2fd6ffc14f050d35bbe27e094 100644 (file)
 
     MSG_INFO_NOTIF(CONNECTING,                              N_CONSOLE,  1, 0, "s1", "",         "",     _("^BG%s^BG is connecting..."), "")
     MSG_INFO_NOTIF(JOIN_CONNECT,                            N_CHATCON,  1, 0, "s1", "",         "",     _("^BG%s^F3 connected"), "")
-    MULTITEAM_INFO(JOIN_CONNECT_TEAM, 4,                    N_CHATCON,  1, 0, "s1", "",         "",     _("^BG%s^F3 connected and joined the ^TC^TT team"), "", NAME)
     MSG_INFO_NOTIF(JOIN_PLAY,                               N_CONSOLE,  1, 0, "s1", "",         "",     _("^BG%s^F3 is now playing"), "")
     MULTITEAM_INFO(JOIN_PLAY_TEAM, 4,                       N_CHATCON,  1, 0, "s1", "",         "",     _("^BG%s^F3 is now playing on the ^TC^TT team"), "", NAME)
 
index ca43d803bc21ff0cc943b16753f096ce684ef42d..9ac3e4299901db21051d4ea2f206fe8636bbfa30 100644 (file)
@@ -532,6 +532,8 @@ void _Movetype_Physics_Frame(entity this, float movedt)
                case MOVETYPE_FLY:
                case MOVETYPE_FLY_WORLDONLY:
                        _Movetype_Physics_Toss(this, movedt);
+                       if(wasfreed(this))
+                               return;
                        _Movetype_LinkEdict(this, true);
                        break;
                case MOVETYPE_PHYSICS:
index 2f4ebb1ff002c9c37278901d70a4838bb0e043e1..f6ab29715a298c07a7bc9c317d0a69d4d9636298 100644 (file)
@@ -809,7 +809,8 @@ bool IsFlying(entity this)
                return false;
        if(this.waterlevel >= WATERLEVEL_SWIMMING)
                return false;
-       traceline(this.origin, this.origin - '0 0 48', MOVE_NORMAL, this);
+       tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 24', MOVE_NORMAL, this);
+       //traceline(this.origin, this.origin - '0 0 48', MOVE_NORMAL, this);
        if(trace_fraction < 1)
                return false;
        return true;
index da48fa698c2086e34049c7fc1ffeb0f9599d5a87..478789dc2e784d51d708382273ac1a106f84a5da 100644 (file)
@@ -15,7 +15,7 @@
 .float swamp_slowdown;
 .float lastflags;
 .float lastground;
-.float wasFlying;
+.bool wasFlying;
 
 .int buttons_old;
 .vector movement_old;
index cde6a519028093268ef95fc568e91184a40d3368..869af4da96533bb90f31f382b35ef0b3ac243a43 100644 (file)
@@ -55,7 +55,7 @@ void PlayerStats_GameReport_AddPlayer(entity e)
        }
 }
 
-void PlayerStats_GameReport_AddTeam(float t)
+void PlayerStats_GameReport_AddTeam(int t)
 {
        if(PS_GR_OUT_DB < 0) { return; }
 
@@ -157,7 +157,7 @@ void PlayerStats_GameReport_FinalizePlayer(entity p)
        strfree(p.playerstats_id);
 }
 
-void PlayerStats_GameReport(float finished)
+void PlayerStats_GameReport(bool finished)
 {
        if(PS_GR_OUT_DB < 0) { return; }
 
index 28f985e27d24a214afc7519a956f70dd79526cef..d27dd0ed1f775038bb904e57327876a84d45314d 100644 (file)
@@ -54,7 +54,7 @@ const string PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD = "achievement-firstblood";
 const string PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM = "achievement-firstvictim";
 
 // delay map switch until this is set
-float PlayerStats_GameReport_DelayMapVote;
+bool PlayerStats_GameReport_DelayMapVote;
 
 // call at initialization
 void PlayerStats_GameReport_Init();
index d46ac9eafc7c36cccbeb07c7d302fe9b25f250d3..49cfb4488c9e478f7bf90dddf95c7787a143d62e 100644 (file)
@@ -128,7 +128,7 @@ CLASS(Sound, Object)
        }
        METHOD(Sound, sound_precache, void(Sound this))
        {
-           TC(Sound, this);
+               TC(Sound, this);
                string s = _Sound_fixpath(this.sound_str());
                if (!s) return;
                profile(sprintf("precache_sound(\"%s\")", s));
index 37813ef716c0bd5f393bc45a1f2fad39036e7b0b..772dbccbd58d870137b69ab4143fc053e3b02e81 100644 (file)
@@ -52,8 +52,6 @@ void ClientState_attach(entity this)
        entcs_attach(this);
        anticheat_init(this);
        W_HitPlotOpen(this);
-
-       bot_clientconnect(this);
 }
 
 void bot_clientdisconnect(entity this);
index 140b619c5ec09cae3f8c62fcf1e87bb6c4b61c2b..0d4d2b92ab2c7221621379a5bf0b77b2d0730146 100644 (file)
@@ -402,7 +402,7 @@ bool have_pickup_item(entity this)
        return true;
 }
 
-void Item_Show (entity e, float mode)
+void Item_Show (entity e, int mode)
 {
        e.effects &= ~(EF_ADDITIVE | EF_STARDUST | EF_FULLBRIGHT | EF_NODEPTHTEST);
        e.ItemStatus &= ~ITS_STAYWEP;
@@ -613,14 +613,18 @@ float adjust_respawntime(float normal_respawntime) {
                return normal_respawntime;
        }
 
-       CheckAllowedTeams(NULL);
-       GetTeamCounts(NULL);
+       entity balance = TeamBalance_CheckAllowedTeams(NULL);
+       TeamBalance_GetTeamCounts(balance, NULL);
        int players = 0;
-       if (c1 != -1) players += c1;
-       if (c2 != -1) players += c2;
-       if (c3 != -1) players += c3;
-       if (c4 != -1) players += c4;
-
+       for (int i = 1; i <= NUM_TEAMS; ++i)
+       {
+               if (TeamBalance_IsTeamAllowed(balance, i))
+               {
+                       players += TeamBalance_GetNumberOfPlayers(balance, i);
+               }
+       }
+       TeamBalance_Destroy(balance);
+       
        if (players >= 2) {
                return normal_respawntime * (r / (players + o) + l);
        } else {
@@ -1313,7 +1317,7 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
                        || (def.instanceOfHealth && def != ITEM_HealthSmall)
                        || (def.instanceOfArmor && def != ITEM_ArmorSmall)
                        || (itemid & (IT_KEY1 | IT_KEY2))
-               ) this.target = "###item###"; // for finding the nearest item using find()
+               ) this.target = "###item###"; // for finding the nearest item using findnearest
 
                Item_ItemsTime_SetTime(this, 0);
        }
index 9fdb0b0925798580c57106a7eb598c24e3a5ad41..4d3f45380069e9cd6fe397265e2c98291d2132ad 100644 (file)
@@ -62,7 +62,7 @@ const float ITEM_RESPAWN_TICKS = 10;
 
 .float item_respawncounter;
 
-void Item_Show (entity e, float mode);
+void Item_Show (entity e, int mode);
 
 void Item_Respawn (entity this);
 
@@ -107,7 +107,7 @@ float weapon_pickupevalfunc(entity player, entity item);
 float ammo_pickupevalfunc(entity player, entity item);
 float healtharmor_pickupevalfunc(entity player, entity item);
 
-.float is_item;
+.bool is_item;
 .entity itemdef;
 void _StartItem(entity this, entity def, float defaultrespawntime, float defaultrespawntimejitter);
 
index 57d644c0448549e13bff834f7cb6fd289d983cc3..62bb2db7cdda28a8e6e63da5cf6024e59f570a3e 100644 (file)
@@ -1,5 +1,7 @@
 #pragma once
 
+const int NUM_TEAMS = 4; ///< Number of teams in the game.
+
 #ifdef TEAMNUMBERS_THAT_ARENT_STUPID
 const int NUM_TEAM_1 = 1;  // red
 const int NUM_TEAM_2 = 2; // blue
@@ -54,11 +56,11 @@ const string STATIC_NAME_TEAM_3 = "Yellow";
 const string STATIC_NAME_TEAM_4 = "Pink";
 
 #ifdef CSQC
-float teamplay;
-float myteam;
+bool teamplay;
+int myteam;
 #endif
 
-string Team_ColorCode(float teamid)
+string Team_ColorCode(int teamid)
 {
        switch(teamid)
        {
@@ -71,7 +73,7 @@ string Team_ColorCode(float teamid)
        return "^7";
 }
 
-vector Team_ColorRGB(float teamid)
+vector Team_ColorRGB(int teamid)
 {
        switch(teamid)
        {
@@ -84,7 +86,7 @@ vector Team_ColorRGB(float teamid)
     return '0 0 0';
 }
 
-string Team_ColorName(float teamid)
+string Team_ColorName(int teamid)
 {
        switch(teamid)
        {
@@ -98,7 +100,7 @@ string Team_ColorName(float teamid)
 }
 
 // used for replacement in filenames or such where the name CANNOT be allowed to be translated
-string Static_Team_ColorName(float teamid)
+string Static_Team_ColorName(int teamid)
 {
        switch(teamid)
        {
@@ -125,12 +127,12 @@ float Team_ColorToTeam(string team_color)
        return -1;
 }
 
-/// \brief Returns whether team is valid.
-/// \param[in] team_ Team to check.
+/// \brief Returns whether team value is valid.
+/// \param[in] team_num Team to check.
 /// \return True if team is valid, false otherwise.
-bool Team_IsValidTeam(int team_)
+bool Team_IsValidTeam(int team_num)
 {
-       switch (team_)
+       switch (team_num)
        {
                case NUM_TEAM_1:
                case NUM_TEAM_2:
@@ -143,12 +145,12 @@ bool Team_IsValidTeam(int team_)
        return false;
 }
 
-/// \brief Returns whether team number is valid.
-/// \param[in] number Team number to check.
-/// \return True if team number is valid, false otherwise.
-bool Team_IsValidNumber(int number)
+/// \brief Returns whether the team index is valid.
+/// \param[in] index Team index to check.
+/// \return True if team index is valid, false otherwise.
+bool Team_IsValidIndex(int index)
 {
-       switch (number)
+       switch (index)
        {
                case 1:
                case 2:
@@ -161,36 +163,60 @@ bool Team_IsValidNumber(int number)
        return false;
 }
 
-float Team_NumberToTeam(float number)
+/// \brief Converts team index into team value.
+/// \param[in] index Team index to convert.
+/// \return Team value.
+int Team_IndexToTeam(int index)
 {
-       switch(number)
+       switch (index)
        {
                case 1: return NUM_TEAM_1;
                case 2: return NUM_TEAM_2;
                case 3: return NUM_TEAM_3;
                case 4: return NUM_TEAM_4;
        }
-
        return -1;
 }
 
-float Team_TeamToNumber(float teamid)
+/// \brief Converts team value into team index.
+/// \param[in] team_num Team value to convert.
+/// \return Team index.
+int Team_TeamToIndex(int team_num)
 {
-       switch(teamid)
+       switch (team_num)
        {
                case NUM_TEAM_1: return 1;
                case NUM_TEAM_2: return 2;
                case NUM_TEAM_3: return 3;
                case NUM_TEAM_4: return 4;
        }
-
        return -1;
 }
 
+/// \brief Converts team value into bit value that is used in team bitmasks.
+/// \param[in] team_num Team value to convert.
+/// \return Team bit.
+int Team_TeamToBit(int team_num)
+{
+       if (!Team_IsValidTeam(team_num))
+       {
+               return 0;
+       }
+       return BIT(Team_TeamToIndex(team_num) - 1);
+}
+
+/// \brief Converts team index into bit value that is used in team bitmasks.
+/// \param[in] index Team index to convert.
+/// \return Team bit.
+int Team_IndexToBit(int index)
+{
+       return BIT(index - 1);
+}
+
 
 // legacy aliases for shitty code
-#define TeamByColor(teamid) (Team_TeamToNumber(teamid) - 1)
-#define ColorByTeam(number) Team_NumberToTeam(number + 1)
+#define TeamByColor(teamid) (Team_TeamToIndex(teamid) - 1)
+#define ColorByTeam(number) Team_IndexToTeam(number + 1)
 
 // useful aliases
 #define Team_ColorName_Lower(teamid) strtolower(Team_ColorName(teamid))
@@ -203,8 +229,8 @@ float Team_TeamToNumber(float teamid)
 #define Team_FullName(teamid) strcat(Team_ColorName(teamid), " ", NAME_TEAM, "^7")
 #define Team_ColoredFullName(teamid) strcat(Team_ColorCode(teamid), Team_ColorName(teamid), " ", NAME_TEAM, "^7")
 
-#define Team_NumberToFullName(number) Team_FullName(Team_NumberToTeam(number))
-#define Team_NumberToColoredFullName(number) Team_ColoredFullName(Team_NumberToTeam(number))
+#define Team_IndexToFullName(index) Team_FullName(Team_IndexToTeam(index))
+#define Team_IndexToColoredFullName(index) Team_ColoredFullName(Team_IndexToTeam(index))
 
 // replace these flags in a string with the strings provided
 #define TCR(input,type,team) strreplace("^TC", COL_TEAM_##team, strreplace("^TT", strtoupper(type##_TEAM_##team), input))
index b68aca16feddd93b6ea01b555b49aa6b17d2c53a..95ee419815a14a0741644b8a84ddcf6bd5ea3b97 100644 (file)
@@ -474,7 +474,7 @@ void turret_projectile_damage(entity this, entity inflictor, entity attacker, fl
 
 entity turret_projectile(entity actor, Sound _snd, float _size, float _health, float _death, float _proj_type, float _cull, float _cli_anim)
 {
-    TC(Sound, _snd);
+       TC(Sound, _snd);
        entity proj;
 
        sound (actor, CH_WEAPON_A, _snd, VOL_BASE, ATTEN_NORM);
index 51ac4bee45f3e035b19fc9895abfbce066e639e6..06c8484ff8eec45d17be6d3f18e0caaa6d1f2c5b 100644 (file)
@@ -21,7 +21,7 @@ float alarm2time;
 
 void vehicle_alarm(entity e, int ch, Sound s0und)
 {
-    TC(Sound, s0und);
+       TC(Sound, s0und);
        if(!autocvar_cl_vehicles_alarm)
                return;
 
index df0f5d91693946c7230fb95d37f0dfb6b773aecd..716dfe8d0c130225041502345a182873aa7c111f 100644 (file)
@@ -251,7 +251,7 @@ entity vehicles_projectile(entity this, string _mzlfx, Sound _mzlsound,
                                                   int _deahtype, float _projtype, float _health,
                                                   bool _cull, bool _clianim, entity _owner)
 {
-    TC(Sound, _mzlsound);
+       TC(Sound, _mzlsound);
        entity proj;
 
        proj = spawn();
@@ -811,7 +811,6 @@ void vehicles_exit(entity vehic, bool eject)
 
        vehicles_exit_running = true;
 
-       // TODO: this was in an IS_CLIENT check, make sure it isn't actually needed!
        if(vehic.vehicle_flags & VHF_PLAYERSLOT)
        {
                vehic.vehicle_exit(vehic, eject);
index c7066e6fbd34720e16d0852f305c6fa36d426323..e78e10a3641d772427a9c053170db903a70e2fb0 100644 (file)
@@ -633,7 +633,7 @@ METHOD(Arc, wr_think, void(entity thiswep, entity actor, .entity weaponentity, i
     }
     else if(fire & 2)
     {
-        if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(arc, bolt_refire)))
+        if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR(arc, bolt_refire)))
         {
             W_Arc_Attack_Bolt(thiswep, actor, weaponentity);
             weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, bolt_refire), w_ready);
index 7e76ffb1cedf9616c6a9cdff802e61074197543d..861def9c733a12562f001c710e1c2cad254bc664 100644 (file)
@@ -255,7 +255,9 @@ void W_Hagar_Attack2_Load_Release(entity actor, .entity weaponentity)
 void W_Hagar_Attack2_Load(Weapon thiswep, entity actor, .entity weaponentity)
 {
        // loadable hagar secondary attack, must always run each frame
-       if(!weapon_prepareattack_check(thiswep, actor, weaponentity, true, -1))
+       if(time < game_starttime || time < actor.race_penalty || timeout_status == TIMEOUT_ACTIVE)
+               return;
+       if (round_handler_IsActive() && !round_handler_IsRoundStarted())
                return;
 
        bool loaded = actor.(weaponentity).hagar_load >= WEP_CVAR_SEC(hagar, load_max);
index 057ef3f03a756b6c3d337a7257fada47c88ebd51..4acceed7184c924af8ffca37017fe3b8794191b4 100644 (file)
@@ -69,7 +69,7 @@ void W_Shotgun_Melee_Think(entity this)
                        + (v_up * swing_factor * WEP_CVAR_SEC(shotgun, melee_swing_up))
                        + (v_right * swing_factor * WEP_CVAR_SEC(shotgun, melee_swing_side)));
 
-               WarpZone_traceline_antilag(this, this.realowner.origin + this.realowner.view_ofs, targpos, false, this.realowner, ((IS_CLIENT(this.realowner)) ? ANTILAG_LATENCY(this.realowner) : 0));
+               WarpZone_traceline_antilag(this.realowner, this.realowner.origin + this.realowner.view_ofs, targpos, false, this.realowner, ((IS_CLIENT(this.realowner)) ? ANTILAG_LATENCY(this.realowner) : 0));
 
                // draw lightning beams for debugging
                //te_lightning2(NULL, targpos, this.realowner.origin + this.realowner.view_ofs + v_forward * 5 - v_up * 5);
@@ -78,7 +78,7 @@ void W_Shotgun_Melee_Think(entity this)
                is_player = (IS_PLAYER(trace_ent) || trace_ent.classname == "body" || IS_MONSTER(trace_ent));
 
                if((trace_fraction < 1) // if trace is good, apply the damage and remove this
-                       && (trace_ent.takedamage == DAMAGE_AIM)
+                       && (trace_ent.takedamage != DAMAGE_NO)
                        && (trace_ent != this.swing_alreadyhit)
                        && (is_player || WEP_CVAR_SEC(shotgun, melee_nonplayerdamage)))
                {
index 3dfac622464a1144ed74096703108d0e9afa8251..841486f5837a9150cf730d77ef23a7d9c8443ca5 100644 (file)
@@ -45,14 +45,14 @@ ERASEABLE
 string CTX(string s)
 {
 #if CTX_CACHE
-               string c = HM_gets(CTX_cache, s);
-               if (c != "") return c;
+       string c = HM_gets(CTX_cache, s);
+       if (c != "") return c;
 #endif
        int p = strstrofs(s, "^", 0);
        string ret = (p < 0) ? s : substring(s, p + 1, -1);
 #if CTX_CACHE
-        LOG_DEBUGF("CTX(\"%s\")", s);
-               HM_sets(CTX_cache, s, ret);
+       LOG_DEBUGF("CTX(\"%s\")", s);
+       HM_sets(CTX_cache, s, ret);
 #endif
        return ret;
 }
index b22ff791501c9a990c93e5d9c7f3dabc2c35f661..e482d7d9ac9b1afab49ae9279ced927e0aa5ce4e 100644 (file)
@@ -326,7 +326,7 @@ CLASS(Object)
     #define remove(this) delete(this)
        METHOD(Object, describe, string(Object this))
        {
-           TC(Object, this);
+               TC(Object, this);
                string s = _("No description");
                if (cvar("developer"))
                {
@@ -340,7 +340,7 @@ CLASS(Object)
        }
        METHOD(Object, display, void(Object this, void(string name, string icon) returns))
        {
-           TC(Object, this);
+               TC(Object, this);
                returns(sprintf("entity %i", this), "nopreview_map");
        }
 ENDCLASS(Object)
index bd45230c97ab61964f43a7153d69242fb896e38c..a06ac8e23100f7ffbc98312edba482164aec1c77 100644 (file)
@@ -49,6 +49,7 @@ void GameCommand(string theCommand)
                LOG_INFO(_("  sync - reloads all cvars on the current menu page"));
                LOG_INFO(_("  directmenu ITEM - select a menu item as main item"));
                LOG_INFO(_("  dumptree - dump the state of the menu as a tree to the console"));
+               LOG_INFO("\n");
 
                LOG_INFO("Generic commands shared by all programs:");
                GenericCommand_macro_help();
index 97f08c98113e520e6d55457356befca52319f28b..c455d2f5ab6c30cd42eee4d01f8dc39edac24f1d 100644 (file)
                }
        }
        AUTOCVAR(menu_scroll_averaging_time, float, 0.16, "smooth scroll averaging time");
-// scroll faster while dragging the scrollbar
+       // scroll faster while dragging the scrollbar
        AUTOCVAR(menu_scroll_averaging_time_pressed, float, 0.06, "smooth scroll averaging time when dragging the scrollbar");
        void ListBox_draw(entity me)
        {
                if (me.scrollPos != me.scrollPosTarget)
                {
                        float averaging_time = (me.pressed == 1)
-                           ? autocvar_menu_scroll_averaging_time_pressed
+                               ? autocvar_menu_scroll_averaging_time_pressed
                                : autocvar_menu_scroll_averaging_time;
                        // this formula works with whatever framerate
                        float f = averaging_time ? exp(-frametime / averaging_time) : 0;
index 9f953f66f542f9a8b9238d65e813a6b5cdf777c7..90221cdf85a43e2731905fe35664ddd57e2440b5 100644 (file)
@@ -168,8 +168,10 @@ void XonoticCampaignList_resizeNotify(entity me, vector relOrigin, vector relSiz
        me.itemAbsSize = '0 0 0';
        SUPER(XonoticCampaignList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
 
-       me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize.y * me.itemHeight));
-       me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize.x * (1 - me.controlWidth)));
+       me.itemAbsSize.y = absSize.y * me.itemHeight;
+       me.itemAbsSize.x = absSize.x * (1 - me.controlWidth);
+       me.realFontSize.y = me.fontSize / me.itemAbsSize.y;
+       me.realFontSize.x = me.fontSize / me.itemAbsSize.x;
        me.realUpperMargin1 = 0.5 * me.realFontSize.y;
        me.realUpperMargin2 = me.realUpperMargin1 + 2 * me.realFontSize.y;
 
index 16d5370f5d7beeef0487001e7aae4c7ad76bb77c..0addd6cbedda7d2bc2f7402b3f9abff336cbfde6 100644 (file)
@@ -92,8 +92,10 @@ void XonoticDemoList_resizeNotify(entity me, vector relOrigin, vector relSize, v
        me.itemAbsSize = '0 0 0';
        SUPER(XonoticDemoList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
 
-       me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize.y * me.itemHeight));
-       me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize.x * (1 - me.controlWidth)));
+       me.itemAbsSize.y = absSize.y * me.itemHeight;
+       me.itemAbsSize.x = absSize.x * (1 - me.controlWidth);
+       me.realFontSize.y = me.fontSize / me.itemAbsSize.y;
+       me.realFontSize.x = me.fontSize / me.itemAbsSize.x;
        me.realUpperMargin = 0.5 * (1 - me.realFontSize.y);
 
        me.columnNameOrigin = me.realFontSize.x;
index 31cc98215d6536745dcea7f5aa153db5b95e53a9..069b22b02d2b3898d691185e597127f77b2c8944 100644 (file)
@@ -80,7 +80,7 @@ void XonoticGameMessageSettingsTab_fill(entity me)
                me.TD(me, 1, 3, e = makeXonoticCheckBoxEx_T(2, 1, "notification_allow_chatboxprint", _("Display all info messages in the chatbox"), "-"));
        me.TR(me);
                me.TD(me, 1, 3, e = makeXonoticCheckBoxEx_T(2, 1, "notification_INFO_QUIT_DISCONNECT", _("Display player statuses in the chatbox"), "-"));
-                       makeMulti(e, "notification_INFO_QUIT_KICK_IDLING notification_INFO_JOIN_CONNECT_TEAM");
+                       makeMulti(e, "notification_INFO_QUIT_KICK_IDLING notification_INFO_JOIN_CONNECT");
        me.TR(me);
        me.TR(me);
                me.TD(me, 1, 3, e = makeXonoticCheckBox_T(0, "notification_CENTER_POWERUP_INVISIBILITY", _("Powerup notifications"), "-"));
index a08e4dbbc5fa13dc4eb51680a1bb551a25780fc0..3703393789eaa1125b6777b170d470612f2bea75 100644 (file)
@@ -101,8 +101,10 @@ void XonoticGametypeList_resizeNotify(entity me, vector relOrigin, vector relSiz
        me.itemAbsSize = '0 0 0';
        SUPER(XonoticGametypeList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
 
-       me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize.y * me.itemHeight));
-       me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize.x * (1 - me.controlWidth)));
+       me.itemAbsSize.y = absSize.y * me.itemHeight;
+       me.itemAbsSize.x = absSize.x * (1 - me.controlWidth);
+       me.realFontSize.y = me.fontSize / me.itemAbsSize.y;
+       me.realFontSize.x = me.fontSize / me.itemAbsSize.x;
        me.realUpperMargin = 0.5 * (1 - me.realFontSize.y);
        me.columnIconOrigin = 0;
        me.columnIconSize = me.itemAbsSize.y / me.itemAbsSize.x;
index d97d7131a473b36c0a46e8935b1efba6078c51d9..92dee8d85ef3cea77a92dd4e30596852d925b3a9 100644 (file)
@@ -146,8 +146,10 @@ void XonoticHUDSkinList_resizeNotify(entity me, vector relOrigin, vector relSize
        me.itemAbsSize = '0 0 0';
        SUPER(XonoticHUDSkinList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
 
-       me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize.y * me.itemHeight));
-       me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize.x * (1 - me.controlWidth)));
+       me.itemAbsSize.y = absSize.y * me.itemHeight;
+       me.itemAbsSize.x = absSize.x * (1 - me.controlWidth);
+       me.realFontSize.y = me.fontSize / me.itemAbsSize.y;
+       me.realFontSize.x = me.fontSize / me.itemAbsSize.x;
        me.realUpperMargin = 0.5 * (1 - me.realFontSize.y);
 
        me.columnNameOrigin = me.realFontSize.x;
index 73ef8a32ae8cfd738852859b0ccb47fa5bf6bbd0..5184ee1fd546a0f90ad3838462a57c005b7b4a9e 100644 (file)
@@ -88,8 +88,10 @@ void XonoticMapList_resizeNotify(entity me, vector relOrigin, vector relSize, ve
        me.itemAbsSize = '0 0 0';
        SUPER(XonoticMapList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
 
-       me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize.y * me.itemHeight));
-       me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize.x * (1 - me.controlWidth)));
+       me.itemAbsSize.y = absSize.y * me.itemHeight;
+       me.itemAbsSize.x = absSize.x * (1 - me.controlWidth);
+       me.realFontSize.y = me.fontSize / me.itemAbsSize.y;
+       me.realFontSize.x = me.fontSize / me.itemAbsSize.x;
        me.realUpperMargin1 = 0.5 * (1 - 2.5 * me.realFontSize.y);
        me.realUpperMargin2 = me.realUpperMargin1 + 1.5 * me.realFontSize.y;
 
index c6033050ae6f45d9157b042039788773b67afa72..e90eef23d3a11d2c63a2aa33798f49522508a396 100644 (file)
@@ -61,8 +61,10 @@ void XonoticPlayerList_resizeNotify(entity me, vector relOrigin, vector relSize,
        me.itemAbsSize = '0 0 0';
        SUPER(XonoticPlayerList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
 
-       me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize.y * me.itemHeight));
-       me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize.x * (1 - me.controlWidth)));
+       me.itemAbsSize.y = absSize.y * me.itemHeight;
+       me.itemAbsSize.x = absSize.x * (1 - me.controlWidth);
+       me.realFontSize.y = me.fontSize / me.itemAbsSize.y;
+       me.realFontSize.x = me.fontSize / me.itemAbsSize.x;
        me.realUpperMargin = 0.5 * (1 - me.realFontSize.y);
 
        // this list does 1 char left and right margin
index c912ba3a72c49bf40ff49c24ee5eaa199a1efb5f..da5fd486eac5265c53a6ccf2b21b2bb291192b89 100644 (file)
@@ -19,8 +19,10 @@ void XonoticPlayList_resizeNotify(entity me, vector relOrigin, vector relSize, v
        me.itemAbsSize = '0 0 0';
        SUPER(XonoticPlayList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
 
-       me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize.y * me.itemHeight));
-       me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize.x * (1 - me.controlWidth)));
+       me.itemAbsSize.y = absSize.y * me.itemHeight;
+       me.itemAbsSize.x = absSize.x * (1 - me.controlWidth);
+       me.realFontSize.y = me.fontSize / me.itemAbsSize.y;
+       me.realFontSize.x = me.fontSize / me.itemAbsSize.x;
        me.realUpperMargin = 0.5 * (1 - me.realFontSize.y);
 
        me.columnNumberOrigin = 0;
index de0adc793815796c0e175f32bf1e6e473b2709e1..9f5ba787aae88c83af4a14b7e02dd0b2f367f5aa 100644 (file)
@@ -97,8 +97,10 @@ void XonoticScreenshotList_resizeNotify(entity me, vector relOrigin, vector relS
        me.itemAbsSize = '0 0 0';
        SUPER(XonoticScreenshotList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
 
-       me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize.y * me.itemHeight));
-       me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize.x * (1 - me.controlWidth)));
+       me.itemAbsSize.y = absSize.y * me.itemHeight;
+       me.itemAbsSize.x = absSize.x * (1 - me.controlWidth);
+       me.realFontSize.y = me.fontSize / me.itemAbsSize.y;
+       me.realFontSize.x = me.fontSize / me.itemAbsSize.x;
        me.realUpperMargin = 0.5 * (1 - me.realFontSize.y);
 
        me.columnNameOrigin = me.realFontSize.x;
index e72ca12e2409813c024fbca7dc98914a1c56da35..4683c45207a018753df987f7d26f1c98ceda86be 100644 (file)
@@ -111,8 +111,10 @@ void XonoticSkinList_resizeNotify(entity me, vector relOrigin, vector relSize, v
        me.itemAbsSize = '0 0 0';
        SUPER(XonoticSkinList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
 
-       me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize.y * me.itemHeight));
-       me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize.x * (1 - me.controlWidth)));
+       me.itemAbsSize.y = absSize.y * me.itemHeight;
+       me.itemAbsSize.x = absSize.x * (1 - me.controlWidth);
+       me.realFontSize.y = me.fontSize / me.itemAbsSize.y;
+       me.realFontSize.x = me.fontSize / me.itemAbsSize.x;
        me.realUpperMargin1 = 0.5 * (1 - 2.5 * me.realFontSize.y);
        me.realUpperMargin2 = me.realUpperMargin1 + 1.5 * me.realFontSize.y;
 
index 6d77e1adf929c1e94f2aa964c7edb7bff88837da..99094b0af2cb125550f23bf1bb6137faf8401ed3 100644 (file)
@@ -55,8 +55,10 @@ void XonoticSoundList_resizeNotify(entity me, vector relOrigin, vector relSize,
        me.itemAbsSize = '0 0 0';
        SUPER(XonoticSoundList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
 
-       me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize.y * me.itemHeight));
-       me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize.x * (1 - me.controlWidth)));
+       me.itemAbsSize.y = absSize.y * me.itemHeight;
+       me.itemAbsSize.x = absSize.x * (1 - me.controlWidth);
+       me.realFontSize.y = me.fontSize / me.itemAbsSize.y;
+       me.realFontSize.x = me.fontSize / me.itemAbsSize.x;
        me.realUpperMargin = 0.5 * (1 - me.realFontSize.y);
 
        me.columnNumberOrigin = 0;
index 401a6eadda0026b5f7e2b6533c40352c597961ea..2c600b6f5289e6d92a03569a0c2dabf03cab3ca7 100644 (file)
@@ -270,8 +270,10 @@ void XonoticStatsList_resizeNotify(entity me, vector relOrigin, vector relSize,
        me.itemAbsSize = '0 0 0';
        SUPER(XonoticStatsList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
 
-       me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize.y * me.itemHeight));
-       me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize.x * (1 - me.controlWidth)));
+       me.itemAbsSize.y = absSize.y * me.itemHeight;
+       me.itemAbsSize.x = absSize.x * (1 - me.controlWidth);
+       me.realFontSize.y = me.fontSize / me.itemAbsSize.y;
+       me.realFontSize.x = me.fontSize / me.itemAbsSize.x;
        me.realUpperMargin = 0.5 * (1 - me.realFontSize.y);
 
 #if 0
index 0ecd7b87725b41f7ca894570f7343836a845d3da..0cddd3b27a01df165978105a753016033b7b5c1c 100644 (file)
@@ -90,7 +90,7 @@ float havocbot_symmetry_origin_order;
 .entity bot_basewaypoint;
 .bool navigation_dynamicgoal;
 void navigation_dynamicgoal_init(entity this, bool initially_static);
-void navigation_dynamicgoal_set(entity this);
+void navigation_dynamicgoal_set(entity this, entity dropper);
 void navigation_dynamicgoal_unset(entity this);
 entity navigation_findnearestwaypoint(entity ent, float walkfromwp);
 void navigation_goalrating_end(entity this);
index 3a9befde403f9ee2a8fb6c2f99076af8ca433d9f..768aa6daee2bb2719c759eb5f9f7dc4354f5f264 100644 (file)
@@ -154,11 +154,6 @@ bool bot_shouldattack(entity this, entity targ)
 
 void bot_lagfunc(entity this, float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4)
 {
-       if(this.flags & FL_INWATER)
-       {
-               this.bot_aimtarg = NULL;
-               return;
-       }
        this.bot_aimtarg = e1;
        this.bot_aimlatency = CS(this).ping; // FIXME?  Shouldn't this be in the lag item?
        //this.bot_aimorigin = v1;
@@ -180,6 +175,8 @@ void bot_aimdir(entity this, vector v, float maxfiredeviation)
        float dist, delta_t, blend;
        vector desiredang, diffang;
 
+       this.bot_aimdir_executed = true;
+
        //dprint("aim ", this.netname, ": old:", vtos(this.v_angle));
        // make sure v_angle is sane first
        this.v_angle_y = this.v_angle.y - floor(this.v_angle.y / 360) * 360;
@@ -245,6 +242,7 @@ void bot_aimdir(entity this, vector v, float maxfiredeviation)
                + this.bot_4th_order_aimfilter * autocvar_bot_ai_aimskill_order_mix_4th
                + this.bot_5th_order_aimfilter * autocvar_bot_ai_aimskill_order_mix_5th
        );
+       desiredang.x = bound(-90, desiredang.x, 90);
 
        // calculate turn angles
        diffang = desiredang - this.bot_mouseaim;
index b8b35f1c203a08968e3b82e7029bbfd17109e6dd..1eb71bc7ff58fee1cdaa2eecdf81003495eb5d91 100644 (file)
@@ -59,6 +59,7 @@ vector shotdir;
 .vector lag5_vec3;
 .vector lag5_vec4;
 
+.bool bot_aimdir_executed;
 .float bot_badaimtime;
 .float bot_aimthinktime;
 .float bot_prevaimtime;
index 2c5627bf63daa7311af2cdcf3e6bd84c7680787c..b80b498e7253fd0a13008d4ec2f0d214c8178734 100644 (file)
@@ -123,6 +123,9 @@ void bot_think(entity this)
        // if dead, just wait until we can respawn
        if (IS_DEAD(this))
        {
+               if (bot_waypoint_queue_owner == this)
+                       bot_waypoint_queue_owner = NULL;
+               this.aistatus = 0;
                CS(this).movement = '0 0 0';
                if (this.deadflag == DEAD_DEAD)
                {
@@ -238,7 +241,7 @@ void bot_setnameandstuff(entity this)
 
        this.bot_config_loaded = true;
 
-       // this is really only a default, JoinBestTeam is called later
+       // this is really only a default, TeamBalance_JoinBestTeam is called later
        setcolor(this, stof(bot_shirt) * 16 + stof(bot_pants));
        this.bot_preferredcolors = this.clientcolors;
 
@@ -249,16 +252,23 @@ void bot_setnameandstuff(entity this)
                name = bot_name;
 
        // number bots with identical names
-       int j = 0;
-       FOREACH_CLIENT(IS_BOT_CLIENT(it), {
-               if(it.cleanname == name)
-                       ++j;
-       });
-       if (j)
-               this.netname = this.netname_freeme = strzone(strcat(prefix, name, "(", ftos(j), ")", suffix));
-       else
+       if (name == "")
+       {
+               name = ftos(etof(this));
                this.netname = this.netname_freeme = strzone(strcat(prefix, name, suffix));
-
+       }
+       else
+       {
+               int j = 0;
+               FOREACH_CLIENT(IS_BOT_CLIENT(it), {
+                       if(it.cleanname == name)
+                               ++j;
+               });
+               if (j)
+                       this.netname = this.netname_freeme = strzone(strcat(prefix, name, "(", ftos(j), ")", suffix));
+               else
+                       this.netname = this.netname_freeme = strzone(strcat(prefix, name, suffix));
+       }
        this.cleanname = strzone(name);
 
        // pick the model and skin
@@ -424,15 +434,15 @@ void bot_clientconnect(entity this)
        else if(this.bot_forced_team==4)
                this.team = NUM_TEAM_4;
        else
-               JoinBestTeam(this, true);
+               TeamBalance_JoinBestTeam(this);
 
        havocbot_setupbot(this);
 }
 
 void bot_removefromlargestteam()
 {
-       CheckAllowedTeams(NULL);
-       GetTeamCounts(NULL);
+       entity balance = TeamBalance_CheckAllowedTeams(NULL);
+       TeamBalance_GetTeamCounts(balance, NULL);
 
        entity best = NULL;
        float besttime = 0;
@@ -451,12 +461,10 @@ void bot_removefromlargestteam()
 
                int thiscount = 0;
 
-               switch(it.team)
+               if (Team_IsValidTeam(it.team))
                {
-                       case NUM_TEAM_1: thiscount = c1; break;
-                       case NUM_TEAM_2: thiscount = c2; break;
-                       case NUM_TEAM_3: thiscount = c3; break;
-                       case NUM_TEAM_4: thiscount = c4; break;
+                       thiscount = TeamBalance_GetNumberOfPlayers(balance,
+                               Team_TeamToIndex(it.team));
                }
 
                if(thiscount > bestcount)
@@ -471,6 +479,7 @@ void bot_removefromlargestteam()
                        best = it;
                }
        });
+       TeamBalance_Destroy(balance);
        if(!bcount)
                return; // no bots to remove
        currentbots = currentbots - 1;
index ca567181bb13fd29331a6dd4c10a37d65f2b2c56..c4da14a4beeb29c7474c273879b34abc1c8411de 100644 (file)
@@ -16,7 +16,7 @@ const int AI_STATUS_JETPACK_FLYING             = BIT(9);
 const int AI_STATUS_JETPACK_LANDING            = BIT(10);
 const int AI_STATUS_STUCK                      = BIT(11); // Cannot reach any goal
 
-.float isbot; // true if this client is actually a bot
+.bool isbot; // true if this client is actually a bot
 .int aistatus;
 
 // Skill system
index 13e1c24c363397de6016ac9f81cce909d298af1c..f5ba20c8a41b1acbe04a1368748eb8cbede98d30 100644 (file)
@@ -18,6 +18,7 @@
 #include <common/items/_mod.qh>
 #include <common/wepent.qh>
 
+#include <common/mapobjects/func/ladder.qh>
 #include <common/mapobjects/teleporters.qh>
 #include <common/mapobjects/trigger/jumppads.qh>
 
@@ -104,6 +105,9 @@ void havocbot_ai(entity this)
        }
        havocbot_aim(this);
        lag_update(this);
+
+       this.bot_aimdir_executed = false;
+
        if (this.bot_aimtarg)
        {
                this.aistatus |= AI_STATUS_ATTACKING;
@@ -140,48 +144,17 @@ void havocbot_ai(entity this)
        {
                this.aistatus |= AI_STATUS_ROAMING;
                this.aistatus &= ~AI_STATUS_ATTACKING;
-
-               vector now, next;
-               float aimdistance,skillblend,distanceblend,blend;
-
-               vector v = get_closer_dest(this.goalcurrent, this.origin);
-               if(this.goalcurrent.wpisbox)
-               {
-                       // avoid a glitch when bot is teleported but teleport waypoint isn't removed yet
-                       if(this.goalstack02 && this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT
-                       && this.lastteleporttime > 0 && time - this.lastteleporttime < 0.15)
-                               v = (this.goalstack02.absmin + this.goalstack02.absmax) * 0.5;
-                       // aim to teleport origin if bot is inside teleport waypoint but hasn't touched the real teleport yet
-                       else if(boxesoverlap(this.goalcurrent.absmin, this.goalcurrent.absmax, this.origin, this.origin))
-                               v = this.goalcurrent.origin;
-               }
-               next = now = v - (this.origin + this.view_ofs);
-               aimdistance = vlen(now);
-
-               //dprint(this.goalstack01.classname,etos(this.goalstack01),"\n");
-               if(
-                       this.goalstack01 != this && this.goalstack01 && !wasfreed(this.goalstack01) && ((this.aistatus & AI_STATUS_RUNNING) == 0) &&
-                       !(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
-               )
-                       next = ((this.goalstack01.absmin + this.goalstack01.absmax) * 0.5) - (this.origin + this.view_ofs);
-
-               skillblend=bound(0,(skill+this.bot_moveskill-2.5)*0.5,1); //lower skill player can't preturn
-               distanceblend=bound(0,aimdistance/autocvar_bot_ai_keyboard_distance,1);
-               blend = skillblend * (1-distanceblend);
-               //v = (now * (distanceblend) + next * (1-distanceblend)) * (skillblend) + now * (1-skillblend);
-               //v = now * (distanceblend) * (skillblend) + next * (1-distanceblend) * (skillblend) + now * (1-skillblend);
-               //v = now * ((1-skillblend) + (distanceblend) * (skillblend)) + next * (1-distanceblend) * (skillblend);
-               v = now + blend * (next - now);
-               //dprint(etos(this), " ");
-               //dprint(vtos(now), ":", vtos(next), "=", vtos(v), " (blend ", ftos(blend), ")\n");
-               //v = now * (distanceblend) + next * (1-distanceblend);
-               if (this.waterlevel < WATERLEVEL_SWIMMING)
-                       v.z = 0;
-               //dprint("walk at:", vtos(v), "\n");
-               //te_lightning2(NULL, this.origin, this.goalcurrent.origin);
-               bot_aimdir(this, v, -1);
        }
+
        havocbot_movetogoal(this);
+       if (!this.bot_aimdir_executed && this.goalcurrent)
+       {
+               // Heading
+               vector dir = get_closer_dest(this.goalcurrent, this.origin);
+               dir -= this.origin + this.view_ofs;
+               dir.z = 0;
+               bot_aimdir(this, dir, -1);
+       }
 
        // if the bot is not attacking, consider reloading weapons
        if (!(this.aistatus & AI_STATUS_ATTACKING))
@@ -488,6 +461,7 @@ void havocbot_movetogoal(entity this)
        vector flatdir;
        vector evadeobstacle;
        vector evadelava;
+       float dodge_enemy_factor = 1;
        float maxspeed;
        //float dist;
        vector dodge;
@@ -525,13 +499,13 @@ void havocbot_movetogoal(entity this)
                {
                        // Calculate brake distance in xy
                        float d = vlen(vec2(this.origin - (this.goalcurrent.absmin + this.goalcurrent.absmax) * 0.5));
-                       float v = vlen(vec2(this.velocity));
-                       float db = ((v ** 2) / (autocvar_g_jetpack_acceleration_side * 2)) + 100;
+                       float vel2 = vlen2(vec2(this.velocity));
+                       float db = (vel2 / (autocvar_g_jetpack_acceleration_side * 2)) + 100;
                        //LOG_INFOF("distance %d, velocity %d, brake at %d ", ceil(d), ceil(v), ceil(db));
                        if(d < db || d < 500)
                        {
                                // Brake
-                               if(v > maxspeed * 0.3)
+                               if (vel2 > (maxspeed * 0.3) ** 2)
                                {
                                        CS(this).movement_x = dir * v_forward * -maxspeed;
                                        return;
@@ -567,8 +541,8 @@ void havocbot_movetogoal(entity this)
                if(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
                {
                        this.aistatus |= AI_STATUS_OUT_JUMPPAD;
-                       navigation_poptouchedgoals(this);
-                       return;
+                       if(navigation_poptouchedgoals(this))
+                               return;
                }
                else if(this.aistatus & AI_STATUS_OUT_JUMPPAD)
                {
@@ -695,7 +669,8 @@ void havocbot_movetogoal(entity this)
 
                        return;
                }
-               else if(GetResourceAmount(this, RESOURCE_HEALTH) + GetResourceAmount(this, RESOURCE_ARMOR) > ROCKETJUMP_DAMAGE())
+               else if(!this.jumppadcount && !this.goalcurrent.wphardwired
+                       && GetResourceAmount(this, RESOURCE_HEALTH) + GetResourceAmount(this, RESOURCE_ARMOR) > ROCKETJUMP_DAMAGE())
                {
                        if(this.velocity.z < 0)
                        {
@@ -748,9 +723,10 @@ void havocbot_movetogoal(entity this)
                else
                        PHYS_INPUT_BUTTON_JUMP(this) = false;
                makevectors(this.v_angle.y * '0 1 0');
-               CS(this).movement_x = dir * v_forward * maxspeed;
-               CS(this).movement_y = dir * v_right * maxspeed;
-               CS(this).movement_z = dir * v_up * maxspeed;
+               vector v = dir * maxspeed;
+               CS(this).movement.x = v * v_forward;
+               CS(this).movement.y = v * v_right;
+               CS(this).movement.z = v * v_up;
        }
 
        // if there is nowhere to go, exit
@@ -799,19 +775,28 @@ void havocbot_movetogoal(entity this)
        if (this.goalcurrent == this.goalentity && this.goalentity_lock_timeout > time)
                locked_goal = true;
 
-       navigation_shortenpath(this);
+       if (navigation_shortenpath(this))
+       {
+               if (vdist(this.origin - this.goalcurrent_prev.origin, <, 50)
+                       && navigation_goalrating_timeout_can_be_anticipated(this))
+                       navigation_goalrating_timeout_force(this);
+       }
 
-       if (IS_MOVABLE(this.goalcurrent))
+       bool goalcurrent_can_be_removed = false;
+       if (IS_PLAYER(this.goalcurrent) || IS_MONSTER(this.goalcurrent))
        {
-               if (IS_DEAD(this.goalcurrent))
+               bool freeze_state_changed = (boolean(STAT(FROZEN, this.goalentity)) != this.goalentity_shouldbefrozen);
+               if (IS_DEAD(this.goalcurrent) || (this.goalentity == this.goalcurrent && freeze_state_changed))
                {
+                       goalcurrent_can_be_removed = true;
+                       // don't remove if not visible
                        if (checkpvs(this.origin + this.view_ofs, this.goalcurrent))
                        {
                                navigation_goalrating_timeout_force(this);
                                return;
                        }
                }
-               else if (this.bot_tracewalk_time < time)
+               else if (!(STAT(FROZEN, this.goalentity)) && this.bot_tracewalk_time < time)
                {
                        set_tracewalk_dest(this.goalcurrent, this.origin, true);
                        if (!(trace_ent == this || tracewalk(this, this.origin, this.mins, this.maxs,
@@ -823,6 +808,7 @@ void havocbot_movetogoal(entity this)
                        this.bot_tracewalk_time = max(time, this.bot_tracewalk_time) + 0.25;
                }
        }
+
        if(!locked_goal)
        {
                // optimize path finding by anticipating goalrating when bot is near a waypoint;
@@ -832,7 +818,7 @@ void havocbot_movetogoal(entity this)
                {
                        if (this.goalcurrent)
                        {
-                               if (IS_MOVABLE(this.goalcurrent) && IS_DEAD(this.goalcurrent))
+                               if (goalcurrent_can_be_removed)
                                {
                                        // remove even if not visible
                                        navigation_goalrating_timeout_force(this);
@@ -872,29 +858,52 @@ void havocbot_movetogoal(entity this)
 
        bool bunnyhop_forbidden = false;
        vector destorg = get_closer_dest(this.goalcurrent, this.origin);
-
-       // in case bot ends up inside the teleport waypoint without touching
-       // the teleport itself, head to the teleport origin
-       if(this.goalcurrent.wpisbox && boxesoverlap(this.goalcurrent.absmin, this.goalcurrent.absmax, this.origin + eZ * this.mins.z, this.origin + eZ * this.maxs.z))
+       if (this.jumppadcount && this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
        {
-               bunnyhop_forbidden = true;
+               // if bot used the jumppad, push towards jumppad origin until jumppad waypoint gets removed
                destorg = this.goalcurrent.origin;
-               if(destorg.z > this.origin.z)
-                       PHYS_INPUT_BUTTON_JUMP(this) = true;
+       }
+       else if (this.goalcurrent.wpisbox)
+       {
+               // if bot is inside the teleport waypoint, head to teleport origin until teleport gets used
+               // do it even if bot is on a ledge above a teleport/jumppad so it doesn't get stuck
+               if (boxesoverlap(this.goalcurrent.absmin, this.goalcurrent.absmax, this.origin + eZ * this.mins.z, this.origin + eZ * this.maxs.z)
+                       || (this.absmin.z > destorg.z && destorg.x == this.origin.x && destorg.y == this.origin.y))
+               {
+                       bunnyhop_forbidden = true;
+                       destorg = this.goalcurrent.origin;
+                       if(destorg.z > this.origin.z)
+                               PHYS_INPUT_BUTTON_JUMP(this) = true;
+               }
        }
 
        diff = destorg - this.origin;
 
-       // 1. stop if too close to target player (even if frozen)
-       // 2. stop if the locked goal has been reached
-       if ((IS_PLAYER(this.goalcurrent) && vdist(diff, <, 80))
-               || (this.goalcurrent == this.goalentity && time < this.goalentity_lock_timeout && vdist(diff, <, 10)))
+       if (this.goalcurrent == this.goalentity && time < this.goalentity_lock_timeout && vdist(diff, <, 10))
        {
+               // stop if the locked goal has been reached
                destorg = this.origin;
-               diff = '0 0 0';
+               diff = dir = '0 0 0';
        }
-
-       dir = normalize(diff);
+       else if (IS_PLAYER(this.goalcurrent) || IS_MONSTER(this.goalcurrent))
+       {
+               if (vdist(diff, <, 80))
+               {
+                       // stop if too close to target player (even if frozen)
+                       destorg = this.origin;
+                       diff = dir = '0 0 0';
+               }
+               else
+               {
+                       // move destorg out of target players, otherwise bot will consider them
+                       // an obstacle that needs to be jumped (especially if frozen)
+                       dir = normalize(diff);
+                       destorg -= dir * PL_MAX_CONST.x * M_SQRT2;
+                       diff = destorg - this.origin;
+               }
+       }
+       else
+               dir = normalize(diff);
        flatdir = (diff.z == 0) ? dir : normalize(vec2(diff));
 
        //if (this.bot_dodgevector_time < time)
@@ -906,9 +915,9 @@ void havocbot_movetogoal(entity this)
 
                this.aistatus &= ~AI_STATUS_DANGER_AHEAD;
                makevectors(this.v_angle.y * '0 1 0');
-               if (this.waterlevel)
+               if (this.waterlevel > WATERLEVEL_WETFEET)
                {
-                       if(this.waterlevel>WATERLEVEL_SWIMMING)
+                       if (this.waterlevel > WATERLEVEL_SWIMMING)
                        {
                                if(!this.goalcurrent)
                                        this.aistatus |= AI_STATUS_OUT_WATER;
@@ -919,7 +928,7 @@ void havocbot_movetogoal(entity this)
                        {
                                dir = flatdir;
                                if(this.velocity.z >= 0 && !(this.watertype == CONTENT_WATER && destorg.z < this.origin.z) &&
-                                       ( !(this.waterlevel == WATERLEVEL_WETFEET && this.watertype == CONTENT_WATER) || this.aistatus & AI_STATUS_OUT_WATER))
+                                       (this.aistatus & AI_STATUS_OUT_WATER))
                                        PHYS_INPUT_BUTTON_JUMP(this) = true;
                                else
                                        PHYS_INPUT_BUTTON_JUMP(this) = false;
@@ -935,16 +944,20 @@ void havocbot_movetogoal(entity this)
                        // jump if going toward an obstacle that doesn't look like stairs we
                        // can walk up directly
                        vector deviation = '0 0 0';
-                       if (this.velocity)
+                       float current_speed = vlen(vec2(this.velocity));
+                       if (current_speed < maxspeed * 0.2)
+                               current_speed = maxspeed * 0.2;
+                       else
                        {
                                deviation = vectoangles(diff) - vectoangles(this.velocity);
                                while (deviation.y < -180) deviation.y += 360;
                                while (deviation.y > 180) deviation.y -= 360;
                        }
+                       float turning = false;
                        vector flat_diff = vec2(diff);
-                       offset = max(32, vlen(vec2(this.velocity)) * cos(deviation.y * DEG2RAD) * 0.2) * flatdir;
+                       offset = max(32, current_speed * cos(deviation.y * DEG2RAD) * 0.3) * flatdir;
                        vector actual_destorg = this.origin + offset;
-                       if (!this.goalstack01 || this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
+                       if (!this.goalstack01 || this.goalcurrent.wpflags & (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_LADDER))
                        {
                                if (vlen2(flat_diff) < vlen2(offset))
                                {
@@ -961,24 +974,53 @@ void havocbot_movetogoal(entity this)
                        {
                                vector next_goal_org = (this.goalstack01.absmin + this.goalstack01.absmax) * 0.5;
                                vector next_dir = normalize(vec2(next_goal_org - destorg));
-                               float next_dist = vlen(vec2(this.origin + offset - destorg));
-                               actual_destorg = vec2(destorg) + next_dist * next_dir;
+                               float dist = vlen(vec2(this.origin + offset - destorg));
+                               // if current and next goal are close to each other make sure
+                               // actual_destorg isn't set beyond next_goal_org
+                               if (dist ** 2 > vlen2(vec2(next_goal_org - destorg)))
+                                       actual_destorg = next_goal_org;
+                               else
+                                       actual_destorg = vec2(destorg) + dist * next_dir;
                                actual_destorg.z = this.origin.z;
+                               turning = true;
                        }
 
-                       tracebox(this.origin, this.mins, this.maxs, actual_destorg, false, this);
-                       if (trace_fraction < 1)
-                       if (trace_plane_normal.z < 0.7)
+                       LABEL(jump_check);
+                       dir = flatdir = normalize(actual_destorg - this.origin);
+
+                       if (turning || fabs(deviation.y) < 50) // don't even try to jump if deviation is too high
                        {
-                               s = trace_fraction;
-                               tracebox(this.origin + stepheightvec, this.mins, this.maxs, actual_destorg + stepheightvec, false, this);
-                               if (trace_fraction < s + 0.01)
-                               if (trace_plane_normal.z < 0.7)
+                               tracebox(this.origin, this.mins, this.maxs, actual_destorg, false, this);
+                               if (trace_fraction < 1 && trace_plane_normal.z < 0.7)
                                {
                                        s = trace_fraction;
-                                       tracebox(this.origin + jumpstepheightvec, this.mins, this.maxs, actual_destorg + jumpstepheightvec, false, this);
-                                       if (trace_fraction > s)
-                                               PHYS_INPUT_BUTTON_JUMP(this) = true;
+                                       tracebox(this.origin + stepheightvec, this.mins, this.maxs, actual_destorg + stepheightvec, false, this);
+                                       if (trace_fraction < s + 0.01 && trace_plane_normal.z < 0.7)
+                                       {
+                                               // found an obstacle
+                                               if (turning && fabs(deviation.y) > 5)
+                                               {
+                                                       // check if the obstacle is still there without turning
+                                                       actual_destorg = destorg;
+                                                       turning = false;
+                                                       this.bot_tracewalk_time = time + 0.25;
+                                                       goto jump_check;
+                                               }
+                                               s = trace_fraction;
+                                               // don't artificially reduce max jump height in real-time
+                                               // (jumpstepheightvec is reduced a bit to make the jumps easy in tracewalk)
+                                               vector jump_height = (IS_ONGROUND(this)) ? stepheightvec + jumpheight_vec : jumpstepheightvec;
+                                               tracebox(this.origin + jump_height, this.mins, this.maxs, actual_destorg + jump_height, false, this);
+                                               if (trace_fraction > s)
+                                                       PHYS_INPUT_BUTTON_JUMP(this) = true;
+                                               else
+                                               {
+                                                       jump_height = stepheightvec + jumpheight_vec / 2;
+                                                       tracebox(this.origin + jump_height, this.mins, this.maxs, actual_destorg + jump_height, false, this);
+                                                       if (trace_fraction > s)
+                                                               PHYS_INPUT_BUTTON_JUMP(this) = true;
+                                               }
+                                       }
                                }
                        }
 
@@ -1065,6 +1107,18 @@ void havocbot_movetogoal(entity this)
                                if(IS_PLAYER(this.goalcurrent))
                                        unreachable = true;
                        }
+
+                       // slow down if bot is in the air and goal is under it
+                       if (!this.goalcurrent.wphardwired
+                               && vdist(flat_diff, <, 250) && this.origin.z - destorg.z > 120
+                               && (!IS_ONGROUND(this) || vdist(vec2(this.velocity), >, maxspeed * 0.3)))
+                       {
+                               // tracebox wouldn't work when bot is still on the ledge
+                               traceline(this.origin, this.origin - '0 0 200', true, this);
+                               if (this.origin.z - trace_endpos.z > 120)
+                                       evadeobstacle = normalize(this.velocity) * -1;
+                       }
+
                        if(unreachable)
                        {
                                navigation_clearroute(this);
@@ -1075,31 +1129,64 @@ void havocbot_movetogoal(entity this)
                }
 
                dodge = havocbot_dodge(this);
-               dodge = dodge * bound(0,0.5+(skill+this.bot_dodgeskill)*0.1,1);
+               if (dodge)
+                       dodge *= bound(0, 0.5 + (skill + this.bot_dodgeskill) * 0.1, 1);
+               dodge += evadeobstacle + evadelava;
                evadelava = evadelava * bound(1,3-(skill+this.bot_dodgeskill),3); //Noobs fear lava a lot and take more distance from it
-               traceline(this.origin, ( ( this.enemy.absmin + this.enemy.absmax ) * 0.5 ), true, NULL);
-               if(IS_PLAYER(trace_ent))
-                       dir = dir * bound(0,(skill+this.bot_dodgeskill)/7,1);
-
-               dir = normalize(dir + dodge + evadeobstacle + evadelava);
+               if (this.enemy)
+               {
+                       traceline(this.origin, (this.enemy.absmin + this.enemy.absmax) * 0.5, true, NULL);
+                       if (IS_PLAYER(trace_ent))
+                               dodge_enemy_factor = bound(0, (skill + this.bot_dodgeskill) / 7, 1);
+               }
        //      this.bot_dodgevector = dir;
        //      this.bot_dodgevector_jumpbutton = PHYS_INPUT_BUTTON_JUMP(this);
        }
 
+       float ladder_zdir = 0;
        if(time < this.ladder_time)
        {
                if(this.goalcurrent.origin.z + this.goalcurrent.mins.z > this.origin.z + this.mins.z)
                {
                        if(this.origin.z + this.mins.z  < this.ladder_entity.origin.z + this.ladder_entity.maxs.z)
-                               dir.z = 1;
+                               ladder_zdir = 1;
                }
                else
                {
                        if(this.origin.z + this.mins.z  > this.ladder_entity.origin.z + this.ladder_entity.mins.z)
-                               dir.z = -1;
+                               ladder_zdir = -1;
+               }
+               if (ladder_zdir)
+               {
+                       if (vdist(flatdir, <, 15))
+                               dir = ladder_zdir * '0 0 1';
+                       else
+                       {
+                               dir.z = ladder_zdir * 1.3;
+                               dir = normalize(dir);
+                       }
                }
        }
 
+       if (this.goalcurrent.wpisbox
+               && boxesoverlap(this.goalcurrent.absmin, this.goalcurrent.absmax, this.origin, this.origin))
+       {
+               // bot is inside teleport waypoint but hasn't touched the real teleport yet
+               // head to teleport origin
+               dir = (this.goalcurrent.origin - this.origin);
+               dir.z = 0;
+               dir = normalize(dir);
+       }
+
+       if (!this.bot_aimdir_executed)
+               bot_aimdir(this, dir, -1);
+
+       if (!ladder_zdir)
+       {
+               dir *= dodge_enemy_factor;
+               dir = normalize(dir + dodge);
+       }
+
        //dir = this.bot_dodgevector;
        //if (this.bot_dodgevector_jumpbutton)
        //      PHYS_INPUT_BUTTON_JUMP(this) = true;
@@ -1453,15 +1540,19 @@ float havocbot_moveto(entity this, vector pos)
                if(autocvar_bot_debug_goalstack)
                        debuggoalstack(this);
 
-               // Heading
-               vector dir = get_closer_dest(this.goalcurrent, this.origin);
-               dir = dir - (this.origin + this.view_ofs);
-               dir.z = 0;
-               bot_aimdir(this, dir, -1);
 
                // Go!
                havocbot_movetogoal(this);
 
+               if (!this.bot_aimdir_executed && this.goalcurrent)
+               {
+                       // Heading
+                       vector dir = get_closer_dest(this.goalcurrent, this.origin);
+                       dir -= this.origin + this.view_ofs;
+                       dir.z = 0;
+                       bot_aimdir(this, dir, -1);
+               }
+
                if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_REACHED)
                {
                        // Step 5: Waypoint reached
@@ -1535,6 +1626,7 @@ void havocbot_setupbot(entity this)
        this.cmd_moveto = havocbot_moveto;
        this.cmd_resetgoal = havocbot_resetgoal;
 
+       // NOTE: bot is not player yet
        havocbot_chooserole(this);
 }
 
index 2f987f674ec8719503137e05452abe5e7701fd1e..b3c0c3ea79191abab45599fe91bc4435631a4866 100644 (file)
@@ -61,5 +61,3 @@ void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrat
  */
 
 .entity draggedby;
-.float ladder_time;
-.entity ladder_entity;
index 9ca2b1208e91a2e828b13ba4ce1646111ac1fc22..1d66df09668a783b4b763a72174e944d2e8e4dcc 100644 (file)
@@ -73,7 +73,7 @@ bool havocbot_goalrating_item_pickable_check_players(entity this, vector org, en
        float enemy_distance = FLOAT_MAX;
        float dist;
 
-       FOREACH_CLIENT(IS_PLAYER(it) && it != this && !IS_DEAD(it),
+       FOREACH_CLIENT(IS_PLAYER(it) && it != this && !(IS_DEAD(it) || STAT(FROZEN, it)),
        {
                if (it.team == this.team)
                {
@@ -113,7 +113,7 @@ void havocbot_goalrating_items(entity this, float ratingscale, vector org, float
 {
        float rating;
        vector o;
-       ratingscale = ratingscale * 0.0001; // items are rated around 10000 already
+       ratingscale = ratingscale * 0.0001;
 
        IL_EACH(g_items, it.bot_pickup,
        {
@@ -121,8 +121,6 @@ void havocbot_goalrating_items(entity this, float ratingscale, vector org, float
                // NOTE: this code assumes each bot rates items in a different frame
                if(it.bot_ratingscale_time == time && ratingscale < it.bot_ratingscale)
                        continue;
-               it.bot_ratingscale_time = time;
-               it.bot_ratingscale = ratingscale;
 
                if(!it.solid)
                {
@@ -175,6 +173,8 @@ void havocbot_goalrating_items(entity this, float ratingscale, vector org, float
                if(!havocbot_goalrating_item_pickable_check_players(this, org, it, o))
                        continue;
 
+               it.bot_ratingscale_time = time;
+               it.bot_ratingscale = ratingscale;
                rating = it.bot_pickupevalfunc(this, it);
                if(rating > 0)
                        navigation_routerating(this, it, rating * ratingscale, 2000);
@@ -191,7 +191,7 @@ void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org
        if(this.waterlevel>WATERLEVEL_WETFEET)
                return;
 
-       ratingscale = ratingscale * 0.00005; // enemies are rated around 20000 already
+       ratingscale = ratingscale * 0.0001;
 
        float t;
        FOREACH_CLIENT(IS_PLAYER(it) && bot_shouldattack(this, it), {
@@ -235,7 +235,7 @@ void havocbot_role_generic(entity this)
        {
                navigation_goalrating_start(this);
                havocbot_goalrating_items(this, 10000, this.origin, 10000);
-               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
+               havocbot_goalrating_enemyplayers(this, 10000, this.origin, 10000);
                havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
                navigation_goalrating_end(this);
 
index 555cfd0ef0a1f4da4beb81ebc73577ced6dd0360..250b7cb09c639e45680e699514958d769b97a686 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <common/constants.qh>
 #include <common/net_linked.qh>
+#include <common/mapobjects/func/ladder.qh>
 #include <common/mapobjects/trigger/jumppads.qh>
 
 .float speed;
@@ -49,12 +50,15 @@ bool navigation_goalrating_timeout(entity this)
 #define MAX_CHASE_DISTANCE 700
 bool navigation_goalrating_timeout_can_be_anticipated(entity this)
 {
-       if(time > this.bot_strategytime - (IS_MOVABLE(this.goalentity) ? 3 : 2))
+       vector gco = (this.goalentity.absmin + this.goalentity.absmax) * 0.5;
+       if (vdist(gco - this.origin, >, autocvar_sv_maxspeed * 1.5)
+               && time > this.bot_strategytime - (IS_MOVABLE(this.goalentity) ? 3 : 2))
+       {
                return true;
+       }
 
        if (this.goalentity.bot_pickup && time > this.bot_strategytime - 5)
        {
-               vector gco = (this.goalentity.absmin + this.goalentity.absmax) * 0.5;
                if(!havocbot_goalrating_item_pickable_check_players(this, this.origin, this.goalentity, gco))
                {
                        this.ignoregoal = this.goalentity;
@@ -75,9 +79,11 @@ void navigation_dynamicgoal_init(entity this, bool initially_static)
                this.nearestwaypointtimeout = time;
 }
 
-void navigation_dynamicgoal_set(entity this)
+void navigation_dynamicgoal_set(entity this, entity dropper)
 {
        this.nearestwaypointtimeout = time;
+       if (dropper && dropper.nearestwaypointtimeout && dropper.nearestwaypointtimeout < time + 2)
+               this.nearestwaypoint = dropper.nearestwaypoint;
        if (this.nearestwaypoint)
                this.nearestwaypointtimeout += 2;
 }
@@ -123,8 +129,18 @@ void set_tracewalk_dest(entity ent, vector org, bool fix_player_dest)
                // z coord is set to ent's min height
                tracewalk_dest.x = bound(wm1.x, org.x, wm2.x);
                tracewalk_dest.y = bound(wm1.y, org.y, wm2.y);
-               tracewalk_dest.z = wm1.z;
-               tracewalk_dest_height = wm2.z - wm1.z; // destination height
+               if ((IS_PLAYER(ent) || IS_MONSTER(ent))
+                       && org.x == tracewalk_dest.x && org.y == tracewalk_dest.y && org.z > tracewalk_dest.z)
+               {
+                       tracewalk_dest.z = wm2.z - PL_MIN_CONST.z;
+                       tracewalk_dest_height = 0;
+                       fix_player_dest = false;
+               }
+               else
+               {
+                       tracewalk_dest.z = wm1.z;
+                       tracewalk_dest_height = wm2.z - wm1.z;
+               }
        }
        else
        {
@@ -265,8 +281,7 @@ bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float e
        int nav_action;
 
        // Analyze starting point
-       traceline(start, start, MOVE_NORMAL, e);
-       if (trace_dpstartcontents & (DPCONTENTS_SLIME | DPCONTENTS_LAVA))
+       if (IN_LAVA(start))
                ignorehazards = true;
 
        tracebox(start, m1, m2, start, MOVE_NOMONSTERS, e);
@@ -732,6 +747,7 @@ void navigation_clearroute(entity this)
        this.goalcurrent_distance_z = FLOAT_MAX;
        this.goalcurrent_distance_time = 0;
        this.goalentity_lock_timeout = 0;
+       this.goalentity_shouldbefrozen = false;
        this.goalentity = NULL;
        this.goalcurrent = NULL;
        this.goalstack01 = NULL;
@@ -900,7 +916,7 @@ entity navigation_findnearestwaypoint_withdist_except(entity ent, float walkfrom
        vector pm2 = ent.origin + ent.maxs;
 
        // do two scans, because box test is cheaper
-       IL_EACH(g_waypoints, it != ent && it != except,
+       IL_EACH(g_waypoints, it != ent && it != except && !(it.wpflags & WAYPOINTFLAG_TELEPORT),
        {
                if(boxesoverlap(pm1, pm2, it.absmin, it.absmax))
                {
@@ -1202,11 +1218,7 @@ void navigation_markroutes_inverted(entity fixed_source_waypoint)
 // updates the best goal according to a weighted calculation of travel cost and item value of a new proposed item
 void navigation_routerating(entity this, entity e, float f, float rangebias)
 {
-       if (!e)
-               return;
-
-       if(e.blacklisted)
-               return;
+       if (!e || e.blacklisted) { return; }
 
        rangebias = waypoint_getlinearcost(rangebias);
        f = waypoint_getlinearcost(f);
@@ -1214,8 +1226,11 @@ void navigation_routerating(entity this, entity e, float f, float rangebias)
        if (IS_PLAYER(e))
        {
                bool rate_wps = false;
-               if((e.flags & FL_INWATER) || (e.flags & FL_PARTIALGROUND))
+               if (e.watertype < CONTENT_WATER || (e.waterlevel > WATERLEVEL_WETFEET && !STAT(FROZEN, e))
+                       || (e.flags & FL_PARTIALGROUND))
+               {
                        rate_wps = true;
+               }
 
                if(!IS_ONGROUND(e))
                {
@@ -1388,7 +1403,6 @@ void navigation_routerating(entity this, entity e, float f, float rangebias)
                nwp = e.nearestwaypoint;
        }
 
-       LOG_DEBUG("-- checking ", e.classname, " (with cost ", ftos(nwp.wpcost), ")");
        if (nwp && nwp.wpcost < 10000000)
        {
                //te_wizspike(nwp.wpnearestpoint);
@@ -1398,12 +1412,12 @@ void navigation_routerating(entity this, entity e, float f, float rangebias)
                else
                        nwptoitem_cost = waypoint_gettravelcost(nwp.wpnearestpoint, goal_org, nwp, e);
                float cost = nwp.wpcost + nwptoitem_cost;
-               LOG_DEBUG(e.classname, " ", ftos(f), "/(1+", ftos(cost), "/", ftos(rangebias), ") = ");
+               LOG_DEBUG("checking ^5", e.classname, "^7 with base rating ^xf04", ftos(f), "^7 and rangebias ^xf40", ftos(rangebias));
                f = f * rangebias / (rangebias + cost);
-               LOG_DEBUG("considering ", e.classname, " (with rating ", ftos(f), ")");
+               LOG_DEBUG("         ^5", e.classname, "^7 with cost ^6", ftos(cost), "^7 and final rating ^2", ftos(f));
                if (navigation_bestrating < f)
                {
-                       LOG_DEBUG("ground path: added goal ", e.classname, " (with rating ", ftos(f), ")");
+                       LOG_DEBUG(" ground path: ^3added goal ^5", e.classname);
                        navigation_bestrating = f;
                        navigation_bestgoal = e;
                }
@@ -1510,12 +1524,12 @@ bool navigation_routetogoal(entity this, entity e, vector startposition)
 }
 
 // shorten path by removing intermediate goals
-void navigation_shortenpath(entity this)
+bool navigation_shortenpath(entity this)
 {
        if (!this.goalstack01 || wasfreed(this.goalstack01))
-               return;
+               return false;
        if (this.bot_tracewalk_time > time)
-               return;
+               return false;
        this.bot_tracewalk_time = max(time, this.bot_tracewalk_time) + 0.25;
 
        bool cut_allowed = false;
@@ -1554,8 +1568,9 @@ void navigation_shortenpath(entity this)
                                        navigation_poproute(this);
                                }
                                while (this.goalcurrent != next);
+                               return true;
                        }
-                       return;
+                       return false;
                }
        }
 
@@ -1576,8 +1591,10 @@ void navigation_shortenpath(entity this)
                {
                        LOG_DEBUG("path optimized for ", this.netname, ", removed a goal from the queue");
                        navigation_poproute(this);
+                       return true;
                }
        }
+       return false;
 }
 
 // removes any currently touching waypoints from the goal stack
@@ -1601,6 +1618,16 @@ int navigation_poptouchedgoals(entity this)
                                this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
                                this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
                        }
+                       if(this.jumppadcount)
+                       {
+                               // remove jumppad waypoint after a random delay to prevent bots getting
+                               // stuck on certain jumppads that require an extra initial horizontal speed
+                               float max_delay = 0.1;
+                               if (vdist(vec2(this.velocity), >, 2 * autocvar_sv_maxspeed))
+                                       max_delay = 0.05;
+                               if (time - this.lastteleporttime < random() * max_delay)
+                                       return removed_goals;
+                       }
                        navigation_poproute(this);
                        this.lastteleporttime = 0;
                        ++removed_goals;
@@ -1675,8 +1702,16 @@ int navigation_poptouchedgoals(entity this)
                        gc_min = this.goalcurrent.origin - '1 1 1' * 12;
                        gc_max = this.goalcurrent.origin + '1 1 1' * 12;
                }
-               if(!boxesoverlap(this.absmin, this.absmax, gc_min, gc_max))
-                       break;
+               if (time < this.ladder_time)
+               {
+                       if (!boxesoverlap(this.absmin, this.absmax - eZ * STAT(PL_MAX, this).z, gc_min, gc_max))
+                               break;
+               }
+               else
+               {
+                       if (!boxesoverlap(this.absmin, this.absmax, gc_min, gc_max))
+                               break;
+               }
 
                // Detect personal waypoints
                if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
@@ -1771,6 +1806,7 @@ void navigation_goalrating_end(entity this)
                        this.aistatus |= AI_STATUS_STUCK;
                }
        }
+       this.goalentity_shouldbefrozen = boolean(STAT(FROZEN, this.goalentity));
 }
 
 void botframe_updatedangerousobjects(float maxupdate)
@@ -1849,6 +1885,17 @@ void navigation_unstuck(entity this)
                                bot_waypoint_queue_bestgoal = bot_waypoint_queue_goal;
                        }
                }
+
+               // move to a random waypoint while bot is searching for a walkable path;
+               // this is usually sufficient to unstuck bots from bad spots or when other
+               // bots of the same team block all their ways
+               if (!bot_waypoint_queue_bestgoal && (!this.goalentity || random() < 0.1))
+               {
+                       navigation_clearroute(this);
+                       navigation_routetogoal(this, bot_waypoint_queue_goal, this.origin);
+                       navigation_goalrating_timeout_expire(this, 1 + random() * 2);
+               }
+
                bot_waypoint_queue_goal = bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal;
 
                if (!bot_waypoint_queue_goal)
@@ -1856,6 +1903,7 @@ void navigation_unstuck(entity this)
                        if (bot_waypoint_queue_bestgoal)
                        {
                                LOG_DEBUG(this.netname, " stuck, reachable waypoint found, heading to it");
+                               navigation_clearroute(this);
                                navigation_routetogoal(this, bot_waypoint_queue_bestgoal, this.origin);
                                navigation_goalrating_timeout_set(this);
                                this.aistatus &= ~AI_STATUS_STUCK;
index f3103cc4fcd39d875708a0612e83c59addd03095..b8b067c3b993cae47c20e7b5219a2d36aa913b9f 100644 (file)
@@ -30,6 +30,7 @@ entity navigation_bestgoal;
 .float goalcurrent_distance_time;
 
 .float goalentity_lock_timeout;
+.bool goalentity_shouldbefrozen;
 
 .entity nearestwaypoint;
 .float nearestwaypointtimeout;
@@ -82,7 +83,7 @@ float bot_waypoint_queue_bestgoalrating;
 .entity bot_basewaypoint;
 .bool navigation_dynamicgoal;
 void navigation_dynamicgoal_init(entity this, bool initially_static);
-void navigation_dynamicgoal_set(entity this);
+void navigation_dynamicgoal_set(entity this, entity dropper);
 void navigation_dynamicgoal_unset(entity this);
 
 .int nav_submerged_state;
@@ -114,7 +115,7 @@ void navigation_markroutes_checkwaypoint(entity w, entity wp, float cost2, vecto
 void navigation_markroutes(entity this, entity fixed_source_waypoint);
 void navigation_markroutes_inverted(entity fixed_source_waypoint);
 void navigation_routerating(entity this, entity e, float f, float rangebias);
-void navigation_shortenpath(entity this);
+bool navigation_shortenpath(entity this);
 int navigation_poptouchedgoals(entity this);
 void navigation_goalrating_start(entity this);
 void navigation_goalrating_end(entity this);
index 674ab634a1c768889ff3ac4025ea07008221b813..bab99b30479e82bc61d90e4553335eb998e65647 100644 (file)
@@ -260,7 +260,7 @@ void waypoint_spawn_fromeditor(entity pl)
                {
                        vector item_org = (it.absmin + it.absmax) * 0.5;
                        item_org.z = it.absmin.z - PL_MIN_CONST.z;
-                       if(vlen(item_org - org) < 30)
+                       if (vlen(item_org - org) < 20)
                        {
                                org = item_org;
                                break;
@@ -293,7 +293,6 @@ void waypoint_spawn_fromeditor(entity pl)
 
 void waypoint_remove(entity wp)
 {
-       // tell all waypoints linked to wp that they need to relink
        IL_EACH(g_waypoints, it != wp,
        {
                if (waypoint_islinked(it, wp))
@@ -718,6 +717,7 @@ bool waypoint_load_links()
 
        bool parse_comments = true;
        float ver = 0;
+       string links_time = string_null;
 
        while ((s = fgets(file)))
        {
@@ -727,13 +727,18 @@ bool waypoint_load_links()
                        {
                                if(substring(s, 2, 17) == "WAYPOINT_VERSION ")
                                        ver = stof(substring(s, 19, -1));
+                               else if(substring(s, 2, 14) == "WAYPOINT_TIME ")
+                                       links_time = substring(s, 16, -1);
                                continue;
                        }
                        else
                        {
-                               if(ver < WAYPOINT_VERSION)
+                               if(ver < WAYPOINT_VERSION || links_time != waypoint_time)
                                {
-                                       LOG_TRACE("waypoint links for this map are outdated.");
+                                       if (links_time != waypoint_time)
+                                               LOG_TRACE("waypoint links for this map are not made for these waypoints.");
+                                       else
+                                               LOG_TRACE("waypoint links for this map are outdated.");
                                        if (g_assault)
                                        {
                                                LOG_TRACE("Assault waypoint links need to be manually updated in the editor");
@@ -996,6 +1001,8 @@ void waypoint_save_links()
        }
 
        fputs(file, strcat("//", "WAYPOINT_VERSION ", ftos_decimals(WAYPOINT_VERSION, 2), "\n"));
+       if (waypoint_time != "")
+               fputs(file, strcat("//", "WAYPOINT_TIME ", waypoint_time, "\n"));
 
        int c = 0;
        IL_EACH(g_waypoints, true,
@@ -1063,7 +1070,12 @@ void waypoint_saveall()
        // (they are read as a waypoint with origin '0 0 0' and flag 0 though)
        fputs(file, strcat("//", "WAYPOINT_VERSION ", ftos_decimals(WAYPOINT_VERSION, 2), "\n"));
        fputs(file, strcat("//", "WAYPOINT_SYMMETRY ", sym_str, "\n"));
-       fputs(file, strcat("//", "\n"));
+
+       strcpy(waypoint_time, strftime(true, "%Y-%m-%d %H:%M:%S"));
+       fputs(file, strcat("//", "WAYPOINT_TIME ", waypoint_time, "\n"));
+       //fputs(file, strcat("//", "\n"));
+       //fputs(file, strcat("//", "\n"));
+       //fputs(file, strcat("//", "\n"));
 
        int c = 0;
        IL_EACH(g_waypoints, true,
@@ -1135,6 +1147,8 @@ float waypoint_loadall()
                                        if (tokens > 2) { sym_param2 = stof(argv(2)); }
                                        if (tokens > 3) { sym_param3 = stof(argv(3)); }
                                }
+                               else if(substring(s, 2, 14) == "WAYPOINT_TIME ")
+                                       strcpy(waypoint_time, substring(s, 16, -1));
                                continue;
                        }
                        else
index 595c2d058fcc1cd82fa1a082ffd29096f90adc3b..34372fe9661f535439b4c815cb6ef5c632dac6c8 100644 (file)
@@ -6,7 +6,8 @@
 // increase by 0.01 when changes require only waypoint relinking
 // increase by 1 when changes require to manually edit waypoints
 // max 2 decimal places, always specified
-#define WAYPOINT_VERSION 1.01
+const float WAYPOINT_VERSION = 1.01;
+string waypoint_time;
 
 // fields you can query using prvm_global server to get some statistics about waypoint linking culling
 float relink_total, relink_walkculled, relink_pvsculled, relink_lengthculled;
index 04172b5eb2b59d74de854c3c1d440ad4c5f7827a..1e3b9e51022685e1eeae3fc94a6778e4eba53fd0 100644 (file)
@@ -45,7 +45,7 @@ void Drag_MoveDrag(entity from, entity to) { }
 
 #else
 
-.float maycheat;
+.bool maycheat;
 float gamestart_sv_cheats;
 
 
@@ -59,7 +59,7 @@ void CheatShutdown()
 {
 }
 
-float CheatsAllowed(entity this, float i, float argc, float fr) // the cheat gets passed as argument for possible future ACL checking
+float CheatsAllowed(entity this, float i, int argc, float fr) // the cheat gets passed as argument for possible future ACL checking
 {
        // dead people cannot cheat
        if(IS_DEAD(this))
index cf114e5f058860e6a55ef47febf11f0e17a31f63..909e89768b866bad6e8516c50ba7e66946301064 100644 (file)
@@ -287,10 +287,8 @@ void PutObserverInServer(entity this)
        if (mutator_returnvalue) {
            // mutator prevents resetting teams+score
        } else {
-               int oldteam = this.team;
-               this.team = -1;  // move this as it is needed to log the player spectating in eventlog
-               MUTATOR_CALLHOOK(Player_ChangedTeam, this, oldteam, this.team);
-        this.frags = FRAGS_SPECTATOR;
+               Player_SetTeamIndex(this, -1);
+               this.frags = FRAGS_SPECTATOR;
         PlayerScore_Clear(this);  // clear scores when needed
     }
 
@@ -302,7 +300,7 @@ void PutObserverInServer(entity this)
                        Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CHAT_NOSPECTATORS);
 
                if(!CS(this).just_joined)
-                       LogTeamchange(this.playerid, -1, 4);
+                       LogTeamchange(this.playerid, -1, TEAM_CHANGE_SPECTATOR);
                else
                        CS(this).just_joined = false;
        }
@@ -521,7 +519,7 @@ void PutPlayerInServer(entity this)
        accuracy_resend(this);
 
        if (this.team < 0)
-               JoinBestTeam(this, true);
+               TeamBalance_JoinBestTeam(this);
 
        entity spot = SelectSpawnPoint(this, false);
        if (!spot) {
@@ -750,12 +748,18 @@ void PutPlayerInServer(entity this)
                this.(weaponentity).weaponname = "";
                this.(weaponentity).m_switchingweapon = WEP_Null;
                this.(weaponentity).cnt = -1;
-
-               W_WeaponFrame(this, weaponentity);
        }
 
        MUTATOR_CALLHOOK(PlayerWeaponSelect, this);
 
+       if (CS(this).impulse) ImpulseCommands(this);
+
+       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+       {
+               .entity weaponentity = weaponentities[slot];
+               W_WeaponFrame(this, weaponentity);
+       }
+
        if (!warmup_stage && !this.alivetime)
                this.alivetime = time;
 
@@ -909,7 +913,7 @@ void ClientKill_Now_TeamChange(entity this)
 {
        if(this.killindicator_teamchange == -1)
        {
-               JoinBestTeam( this, true );
+               TeamBalance_JoinBestTeam(this);
        }
        else if(this.killindicator_teamchange == -2)
        {
@@ -1169,6 +1173,76 @@ void ClientPreConnect(entity this)
 }
 #endif
 
+string GetClientVersionMessage(entity this)
+{
+       if (CS(this).version_mismatch) {
+               if(CS(this).version < autocvar_gameversion) {
+                       return strcat("This is Xonotic ", autocvar_g_xonoticversion,
+                               "\n^3Your client version is outdated.\n\n\n### YOU WON'T BE ABLE TO PLAY ON THIS SERVER ###\n\n\nPlease update!!!^8");
+               } else {
+                       return strcat("This is Xonotic ", autocvar_g_xonoticversion,
+                               "\n^3This server is using an outdated Xonotic version.\n\n\n ### THIS SERVER IS INCOMPATIBLE AND THUS YOU CANNOT JOIN ###.^8");
+               }
+       } else {
+               return strcat("Welcome to Xonotic ", autocvar_g_xonoticversion);
+       }
+}
+
+string getwelcomemessage(entity this)
+{
+       MUTATOR_CALLHOOK(BuildMutatorsPrettyString, "");
+       string modifications = M_ARGV(0, string);
+
+       if(g_weaponarena)
+       {
+               if(g_weaponarena_random)
+                       modifications = strcat(modifications, ", ", ftos(g_weaponarena_random), " of ", g_weaponarena_list, " Arena");
+               else
+                       modifications = strcat(modifications, ", ", g_weaponarena_list, " Arena");
+       }
+       else if(cvar("g_balance_blaster_weaponstartoverride") == 0)
+               modifications = strcat(modifications, ", No start weapons");
+       if(cvar("sv_gravity") < stof(cvar_defstring("sv_gravity")))
+               modifications = strcat(modifications, ", Low gravity");
+       if(g_weapon_stay && !g_cts)
+               modifications = strcat(modifications, ", Weapons stay");
+       if(g_jetpack)
+               modifications = strcat(modifications, ", Jet pack");
+       if(autocvar_g_powerups == 0)
+               modifications = strcat(modifications, ", No powerups");
+       if(autocvar_g_powerups > 0)
+               modifications = strcat(modifications, ", Powerups");
+       modifications = substring(modifications, 2, strlen(modifications) - 2);
+
+       string versionmessage = GetClientVersionMessage(this);
+       string s = strcat(versionmessage, "^8\n^8\nmatch type is ^1", gamemode_name, "^8\n");
+
+       if(modifications != "")
+               s = strcat(s, "^8\nactive modifications: ^3", modifications, "^8\n");
+
+       if(cache_lastmutatormsg != autocvar_g_mutatormsg)
+       {
+               strcpy(cache_lastmutatormsg, autocvar_g_mutatormsg);
+               strcpy(cache_mutatormsg, cache_lastmutatormsg);
+       }
+
+       if (cache_mutatormsg != "") {
+               s = strcat(s, "\n\n^8special gameplay tips: ^7", cache_mutatormsg);
+       }
+
+       string mutator_msg = "";
+       MUTATOR_CALLHOOK(BuildGameplayTipsString, mutator_msg);
+       mutator_msg = M_ARGV(0, string);
+
+       s = strcat(s, mutator_msg); // trust that the mutator will do proper formatting
+
+       string motd = autocvar_sv_motd;
+       if (motd != "") {
+               s = strcat(s, "\n\n^8MOTD: ^7", strreplace("\\n", "\n", motd));
+       }
+       return s;
+}
+
 /**
 =============
 ClientConnect
@@ -1189,6 +1263,10 @@ void ClientConnect(entity this)
        TRANSMUTE(Client, this);
        CS(this).version_nagtime = time + 10 + random() * 10;
 
+       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_JOIN_CONNECT, this.netname);
+
+       bot_clientconnect(this);
+
        // identify the right forced team
        if (autocvar_g_campaign)
        {
@@ -1222,11 +1300,6 @@ void ClientConnect(entity this)
        }
        if (!teamplay && this.team_forced > 0) this.team_forced = 0;
 
-       int playerid_save = this.playerid;
-       this.playerid = 0; // silent
-       JoinBestTeam(this, false); // if the team number is valid, keep it
-       this.playerid = playerid_save;
-
        TRANSMUTE(Observer, this);
 
        PlayerStats_GameReport_AddEvent(sprintf("kills-%d", this.playerid));
@@ -1240,15 +1313,8 @@ void ClientConnect(entity this)
        if (autocvar_sv_eventlog)
                GameLogEcho(strcat(":join:", ftos(this.playerid), ":", ftos(etof(this)), ":", ((IS_REAL_CLIENT(this)) ? this.netaddress : "bot"), ":", playername(this, false)));
 
-       LogTeamchange(this.playerid, this.team, 1);
-
        CS(this).just_joined = true;  // stop spamming the eventlog with additional lines when the client connects
 
-       if(teamplay && IS_PLAYER(this))
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_JOIN_CONNECT_TEAM), this.netname);
-       else
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_JOIN_CONNECT, this.netname);
-
        stuffcmd(this, clientstuff, "\n");
        stuffcmd(this, "cl_particles_reloadeffects\n"); // TODO do we still need this?
 
@@ -1260,12 +1326,9 @@ void ClientConnect(entity this)
        // notify about available teams
        if (teamplay)
        {
-               CheckAllowedTeams(this);
-               int t = 0;
-               if (c1 >= 0) t |= BIT(0);
-               if (c2 >= 0) t |= BIT(1);
-               if (c3 >= 0) t |= BIT(2);
-               if (c4 >= 0) t |= BIT(3);
+               entity balance = TeamBalance_CheckAllowedTeams(this);
+               int t = TeamBalance_GetAllowedTeams(balance);
+               TeamBalance_Destroy(balance);
                stuffcmd(this, sprintf("set _teams_available %d\n", t));
        }
        else
@@ -1517,7 +1580,7 @@ void DebugPrintToChatTeam(int team_num, string text)
 
 void play_countdown(entity this, float finished, Sound samp)
 {
-    TC(Sound, samp);
+       TC(Sound, samp);
        if(IS_REAL_CLIENT(this))
                if(floor(finished - time - frametime) != floor(finished - time))
                        if(finished - time < 6)
@@ -1797,7 +1860,7 @@ spectate mode routines
 
 void SpectateCopy(entity this, entity spectatee)
 {
-    TC(Client, this); TC(Client, spectatee);
+       TC(Client, this); TC(Client, spectatee);
 
        MUTATOR_CALLHOOK(SpectateCopy, spectatee, this);
        PS(this) = PS(spectatee);
@@ -2050,7 +2113,7 @@ void Join(entity this)
 
        if(!this.team_selected)
        if(autocvar_g_campaign || autocvar_g_balance_teams)
-               JoinBestTeam(this, true);
+               TeamBalance_JoinBestTeam(this);
 
        if(autocvar_g_campaign)
                campaign_bots_may_start = true;
@@ -2061,7 +2124,9 @@ void Join(entity this)
 
        if(IS_PLAYER(this))
        if(teamplay && this.team != -1)
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_JOIN_PLAY_TEAM), this.netname);
+       {
+               //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;
index da495f7962f89210697c4dead7802da99df03d78..fb63b057e23c1cc250da3741ae7fcf65af058ac9 100644 (file)
@@ -18,7 +18,7 @@
 //  Last updated: December 29th, 2011
 // =====================================================
 
-void BanCommand_ban(float request, float argc, string command)
+void BanCommand_ban(int request, int argc, string command)
 {
        switch (request)
        {
@@ -54,7 +54,7 @@ void BanCommand_ban(float request, float argc, string command)
        }
 }
 
-void BanCommand_banlist(float request)
+void BanCommand_banlist(int request)
 {
        switch (request)
        {
@@ -75,7 +75,7 @@ void BanCommand_banlist(float request)
        }
 }
 
-void BanCommand_kickban(float request, float argc, string command)
+void BanCommand_kickban(int request, int argc, string command)
 {
        switch (request)
        {
@@ -122,7 +122,7 @@ void BanCommand_kickban(float request, float argc, string command)
        }
 }
 
-void BanCommand_mute(float request, float argc, string command)  // TODO: Add a sort of mute-"ban" which allows players to be muted based on IP/cryptokey
+void BanCommand_mute(int request, int argc, string command)  // TODO: Add a sort of mute-"ban" which allows players to be muted based on IP/cryptokey
 {
        switch (request)
        {
@@ -157,7 +157,7 @@ void BanCommand_mute(float request, float argc, string command)  // TODO: Add a
        }
 }
 
-void BanCommand_unban(float request, float argc)
+void BanCommand_unban(int request, int argc)
 {
        switch (request)
        {
@@ -203,7 +203,7 @@ void BanCommand_unban(float request, float argc)
        }
 }
 
-void BanCommand_unmute(float request, float argc)
+void BanCommand_unmute(int request, int argc)
 {
        switch (request)
        {
@@ -240,7 +240,7 @@ void BanCommand_unmute(float request, float argc)
 
 /* use this when creating a new command, making sure to place it in alphabetical order... also,
 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
-void BanCommand_(float request)
+void BanCommand_(int request)
 {
     switch(request)
     {
@@ -285,7 +285,7 @@ void BanCommand_macro_help()
 #undef BAN_COMMAND
 }
 
-float BanCommand_macro_command(float argc, string command)
+float BanCommand_macro_command(int argc, string command)
 {
        #define BAN_COMMAND(name, function, description) \
                { if (name == strtolower(argv(0))) { function; return true; } }
@@ -296,7 +296,7 @@ float BanCommand_macro_command(float argc, string command)
        return false;
 }
 
-float BanCommand_macro_usage(float argc)
+float BanCommand_macro_usage(int argc)
 {
        #define BAN_COMMAND(name, function, description) \
                { if (name == strtolower(argv(1))) { function; return true; } }
@@ -318,7 +318,7 @@ void BanCommand_macro_write_aliases(float fh)
 
 float BanCommand(string command)
 {
-       float argc = tokenize_console(command);
+       int argc = tokenize_console(command);
 
        // Guide for working with argc arguments by example:
        // argc:   1    - 2      - 3     - 4
index 3cbaaf978e2950d7ad241a4147fab59953db3c11..ae16532ecfb37d77fbbc3e38ec32a814c0cfd6f0 100644 (file)
@@ -12,4 +12,4 @@
 void BanCommand_macro_write_aliases(float fh);
 
 void BanCommand_macro_help();
-float BanCommand_macro_usage(float argc);
+float BanCommand_macro_usage(int argc);
index 9b7a0f6574fb78cf3636d8325b4bb7479f59ae47..443aac085d3f652872b9f7b5135bb8d16b9f6ef0 100644 (file)
@@ -72,7 +72,7 @@ bool SV_ParseClientCommand_floodcheck(entity this)
 //  Command Sub-Functions
 // =======================
 
-void ClientCommand_autoswitch(entity caller, float request, float argc)
+void ClientCommand_autoswitch(entity caller, int request, int argc)
 {
        switch (request)
        {
@@ -97,7 +97,7 @@ void ClientCommand_autoswitch(entity caller, float request, float argc)
        }
 }
 
-void ClientCommand_clientversion(entity caller, float request, float argc)  // internal command, used only by code
+void ClientCommand_clientversion(entity caller, int request, int argc)  // internal command, used only by code
 {
        switch (request)
        {
@@ -140,7 +140,7 @@ void ClientCommand_clientversion(entity caller, float request, float argc)  // i
        }
 }
 
-void ClientCommand_mv_getpicture(entity caller, float request, float argc)  // internal command, used only by code
+void ClientCommand_mv_getpicture(entity caller, int request, int argc)  // internal command, used only by code
 {
        switch (request)
        {
@@ -165,7 +165,7 @@ void ClientCommand_mv_getpicture(entity caller, float request, float argc)  // i
        }
 }
 
-void ClientCommand_join(entity caller, float request)
+void ClientCommand_join(entity caller, int request)
 {
        switch (request)
        {
@@ -189,7 +189,7 @@ void ClientCommand_join(entity caller, float request)
        }
 }
 
-void ClientCommand_physics(entity caller, float request, float argc)
+void ClientCommand_physics(entity caller, int request, int argc)
 {
        switch (request)
        {
@@ -229,7 +229,7 @@ void ClientCommand_physics(entity caller, float request, float argc)
        }
 }
 
-void ClientCommand_ready(entity caller, float request)  // todo: anti-spam for toggling readyness
+void ClientCommand_ready(entity caller, int request)  // todo: anti-spam for toggling readyness
 {
        switch (request)
        {
@@ -278,7 +278,7 @@ void ClientCommand_ready(entity caller, float request)  // todo: anti-spam for t
        }
 }
 
-void ClientCommand_say(entity caller, float request, float argc, string command)
+void ClientCommand_say(entity caller, int request, int argc, string command)
 {
        switch (request)
        {
@@ -298,7 +298,7 @@ void ClientCommand_say(entity caller, float request, float argc, string command)
        }
 }
 
-void ClientCommand_say_team(entity caller, float request, float argc, string command)
+void ClientCommand_say_team(entity caller, int request, int argc, string command)
 {
        switch (request)
        {
@@ -319,7 +319,7 @@ void ClientCommand_say_team(entity caller, float request, float argc, string com
 }
 
 .bool team_selected;
-void ClientCommand_selectteam(entity caller, float request, float argc)
+void ClientCommand_selectteam(entity caller, int request, int argc)
 {
        switch (request)
        {
@@ -394,13 +394,16 @@ void ClientCommand_selectteam(entity caller, float request, float argc)
                        if ((selection != -1) && autocvar_g_balance_teams &&
                                autocvar_g_balance_teams_prevent_imbalance)
                        {
-                               CheckAllowedTeams(caller);
-                               GetTeamCounts(caller);
-                               if ((BIT(Team_TeamToNumber(selection) - 1) & FindBestTeams(caller, false)) == 0)
+                               entity balance = TeamBalance_CheckAllowedTeams(caller);
+                               TeamBalance_GetTeamCounts(balance, caller);
+                               if ((Team_IndexToBit(Team_TeamToIndex(selection)) &
+                                       TeamBalance_FindBestTeams(balance, caller, false)) == 0)
                                {
                                        Send_Notification(NOTIF_ONE, caller, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM);
+                                       TeamBalance_Destroy(balance);
                                        return;
                                }
+                               TeamBalance_Destroy(balance);
                        }
                        ClientKill_TeamChange(caller, selection);
                        if (!IS_PLAYER(caller))
@@ -421,7 +424,7 @@ void ClientCommand_selectteam(entity caller, float request, float argc)
        }
 }
 
-void ClientCommand_selfstuff(entity caller, float request, string command)
+void ClientCommand_selfstuff(entity caller, int request, string command)
 {
        switch (request)
        {
@@ -445,7 +448,7 @@ void ClientCommand_selfstuff(entity caller, float request, string command)
        }
 }
 
-void ClientCommand_sentcvar(entity caller, float request, float argc, string command)
+void ClientCommand_sentcvar(entity caller, int request, int argc, string command)
 {
        switch (request)
        {
@@ -479,7 +482,7 @@ void ClientCommand_sentcvar(entity caller, float request, float argc, string com
        }
 }
 
-void ClientCommand_spectate(entity caller, float request)
+void ClientCommand_spectate(entity caller, int request)
 {
        switch (request)
        {
@@ -519,7 +522,7 @@ void ClientCommand_spectate(entity caller, float request)
        }
 }
 
-void ClientCommand_suggestmap(entity caller, float request, float argc)
+void ClientCommand_suggestmap(entity caller, int request, int argc)
 {
        switch (request)
        {
@@ -543,7 +546,7 @@ void ClientCommand_suggestmap(entity caller, float request, float argc)
        }
 }
 
-void ClientCommand_tell(entity caller, float request, float argc, string command)
+void ClientCommand_tell(entity caller, int request, int argc, string command)
 {
        switch (request)
        {
@@ -600,7 +603,7 @@ void ClientCommand_tell(entity caller, float request, float argc, string command
        }
 }
 
-void ClientCommand_voice(entity caller, float request, float argc, string command)
+void ClientCommand_voice(entity caller, int request, int argc, string command)
 {
        switch (request)
        {
@@ -637,7 +640,7 @@ void ClientCommand_voice(entity caller, float request, float argc, string comman
 
 /* use this when creating a new command, making sure to place it in alphabetical order... also,
 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
-void ClientCommand_(entity caller, float request)
+void ClientCommand_(entity caller, int request)
 {
     switch(request)
     {
@@ -667,8 +670,9 @@ void ClientCommand_(entity caller, float request)
 #define CLIENT_COMMANDS(ent, request, arguments, command) \
        CLIENT_COMMAND("autoswitch", ClientCommand_autoswitch(ent, request, arguments), "Whether or not to switch automatically when getting a better weapon") \
        CLIENT_COMMAND("clientversion", ClientCommand_clientversion(ent, request, arguments), "Release version of the game") \
-       CLIENT_COMMAND("mv_getpicture", ClientCommand_mv_getpicture(ent, request, arguments), "Retrieve mapshot picture from the server") \
        CLIENT_COMMAND("join", ClientCommand_join(ent, request), "Become a player in the game") \
+       CLIENT_COMMAND("minigame", ClientCommand_minigame(ent, request, arguments, command), "Start a minigame") \
+       CLIENT_COMMAND("mv_getpicture", ClientCommand_mv_getpicture(ent, request, arguments), "Retrieve mapshot picture from the server") \
        CLIENT_COMMAND("physics", ClientCommand_physics(ent, request, arguments), "Change physics set") \
        CLIENT_COMMAND("ready", ClientCommand_ready(ent, request), "Qualify as ready to end warmup stage (or restart server if allowed)") \
        CLIENT_COMMAND("say", ClientCommand_say(ent, request, arguments, command), "Print a message to chat to all players") \
@@ -680,7 +684,6 @@ void ClientCommand_(entity caller, float request)
        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") \
-       CLIENT_COMMAND("minigame", ClientCommand_minigame(ent, request, arguments, command), "Start a minigame") \
        /* nothing */
 
 void ClientCommand_macro_help(entity caller)
@@ -692,7 +695,7 @@ void ClientCommand_macro_help(entity caller)
 #undef CLIENT_COMMAND
 }
 
-float ClientCommand_macro_command(float argc, entity caller, string command)
+float ClientCommand_macro_command(int argc, entity caller, string command)
 {
        #define CLIENT_COMMAND(name, function, description) \
                { if (name == strtolower(argv(0))) { function; return true; } }
@@ -703,7 +706,7 @@ float ClientCommand_macro_command(float argc, entity caller, string command)
        return false;
 }
 
-float ClientCommand_macro_usage(float argc, entity caller)
+float ClientCommand_macro_usage(int argc, entity caller)
 {
        #define CLIENT_COMMAND(name, function, description) \
                { if (name == strtolower(argv(1))) { function; return true; } }
@@ -741,7 +744,7 @@ void SV_ParseClientCommand(entity this, string command)
        // if we're banned, don't even parse the command
        if (Ban_MaybeEnforceBanOnce(this)) return;
 
-       float argc = tokenize_console(command);
+       int argc = tokenize_console(command);
 
        // Guide for working with argc arguments by example:
        // argc:   1    - 2      - 3     - 4
index cb8ab239fbebd1ac74b4781982d3d93ed14f43ac..643afa3f177887ff8ab2754a30c882eb90263231 100644 (file)
@@ -76,7 +76,7 @@ float VerifyClientNumber(float tmp_number)
        else return true;
 }
 
-entity GetIndexedEntity(float argc, float start_index)
+entity GetIndexedEntity(int argc, float start_index)
 {
        entity selection;
        float tmp_number, index;
@@ -280,7 +280,7 @@ void timeout_handler_think(entity this)
 //  Common commands used in both sv_cmd.qc and cmd.qc
 // ===================================================
 
-void CommonCommand_cvar_changes(float request, entity caller)
+void CommonCommand_cvar_changes(int request, entity caller)
 {
        switch (request)
        {
@@ -301,7 +301,7 @@ void CommonCommand_cvar_changes(float request, entity caller)
        }
 }
 
-void CommonCommand_cvar_purechanges(float request, entity caller)
+void CommonCommand_cvar_purechanges(int request, entity caller)
 {
        switch (request)
        {
@@ -469,7 +469,7 @@ void CommonCommand_editmob(int request, entity caller, int argc)
        }
 }
 
-void CommonCommand_info(float request, entity caller, float argc)
+void CommonCommand_info(int request, entity caller, int argc)
 {
        switch (request)
        {
@@ -493,7 +493,7 @@ void CommonCommand_info(float request, entity caller, float argc)
        }
 }
 
-void CommonCommand_ladder(float request, entity caller)
+void CommonCommand_ladder(int request, entity caller)
 {
        switch (request)
        {
@@ -513,7 +513,7 @@ void CommonCommand_ladder(float request, entity caller)
        }
 }
 
-void CommonCommand_lsmaps(float request, entity caller)
+void CommonCommand_lsmaps(int request, entity caller)
 {
        switch (request)
        {
@@ -533,7 +533,7 @@ void CommonCommand_lsmaps(float request, entity caller)
        }
 }
 
-void CommonCommand_printmaplist(float request, entity caller)
+void CommonCommand_printmaplist(int request, entity caller)
 {
        switch (request)
        {
@@ -553,7 +553,7 @@ void CommonCommand_printmaplist(float request, entity caller)
        }
 }
 
-void CommonCommand_rankings(float request, entity caller)
+void CommonCommand_rankings(int request, entity caller)
 {
        switch (request)
        {
@@ -573,7 +573,7 @@ void CommonCommand_rankings(float request, entity caller)
        }
 }
 
-void CommonCommand_records(float request, entity caller)
+void CommonCommand_records(int request, entity caller)
 {
        switch (request)
        {
@@ -601,7 +601,7 @@ void CommonCommand_records(float request, entity caller)
        }
 }
 
-void CommonCommand_teamstatus(float request, entity caller)
+void CommonCommand_teamstatus(int request, entity caller)
 {
        switch (request)
        {
@@ -621,7 +621,7 @@ void CommonCommand_teamstatus(float request, entity caller)
        }
 }
 
-void CommonCommand_time(float request, entity caller)
+void CommonCommand_time(int request, entity caller)
 {
        switch (request)
        {
@@ -632,8 +632,8 @@ void CommonCommand_time(float request, entity caller)
                        print_to(caller, strcat("realtime = ", ftos(gettime(GETTIME_REALTIME))));
                        print_to(caller, strcat("hires = ", ftos(gettime(GETTIME_HIRES))));
                        print_to(caller, strcat("uptime = ", ftos(gettime(GETTIME_UPTIME))));
-                       print_to(caller, strcat("localtime = ", strftime(true, "%a %b %e %H:%M:%S %Z %Y")));
-                       print_to(caller, strcat("gmtime = ", strftime(false, "%a %b %e %H:%M:%S %Z %Y")));
+                       print_to(caller, strcat("localtime = ", strftime(true, "%a %b %d %H:%M:%S %Z %Y")));
+                       print_to(caller, strcat("gmtime = ", strftime(false, "%a %b %d %H:%M:%S %Z %Y")));
                        return;
                }
 
@@ -647,7 +647,7 @@ void CommonCommand_time(float request, entity caller)
        }
 }
 
-void CommonCommand_timein(float request, entity caller)
+void CommonCommand_timein(int request, entity caller)
 {
        switch (request)
        {
@@ -702,7 +702,7 @@ void CommonCommand_timein(float request, entity caller)
        }
 }
 
-void CommonCommand_timeout(float request, entity caller)  // DEAR GOD THIS COMMAND IS TERRIBLE.
+void CommonCommand_timeout(int request, entity caller)  // DEAR GOD THIS COMMAND IS TERRIBLE.
 {
        switch (request)
        {
@@ -771,7 +771,7 @@ void CommonCommand_timeout(float request, entity caller)  // DEAR GOD THIS COMMA
        }
 }
 
-void CommonCommand_who(float request, entity caller, float argc)
+void CommonCommand_who(int request, entity caller, int argc)
 {
        switch (request)
        {
@@ -836,7 +836,7 @@ void CommonCommand_who(float request, entity caller, float argc)
 
 /* use this when creating a new command, making sure to place it in alphabetical order... also,
 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
-void CommonCommand_(float request, entity caller)
+void CommonCommand_(int request, entity caller)
 {
     switch(request)
     {
index 13cbfe49e127ece70856a11fcd58f670c5750fa6..f03a815de26b6de896ddee64a71dc6e05e0476c2 100644 (file)
@@ -81,7 +81,7 @@ string GetClientErrorString_color(float clienterror, string original_input, stri
 // is this entity number even in the possible range of entities?
 float VerifyClientNumber(float tmp_number);
 
-entity GetIndexedEntity(float argc, float start_index);
+entity GetIndexedEntity(int argc, float start_index);
 
 // find a player which matches the input string, and return their entity
 entity GetFilteredEntity(string input);
@@ -105,33 +105,33 @@ void timeout_handler_think(entity this);
 //  Common commands used in both sv_cmd.qc and cmd.qc
 // ===================================================
 
-void CommonCommand_cvar_changes(float request, entity caller);
+void CommonCommand_cvar_changes(int request, entity caller);
 
-void CommonCommand_cvar_purechanges(float request, entity caller);
+void CommonCommand_cvar_purechanges(int request, entity caller);
 
-void CommonCommand_editmob(float request, entity caller, float argc);
+void CommonCommand_editmob(int request, entity caller, int argc);
 
-void CommonCommand_info(float request, entity caller, float argc);
+void CommonCommand_info(int request, entity caller, int argc);
 
-void CommonCommand_ladder(float request, entity caller);
+void CommonCommand_ladder(int request, entity caller);
 
-void CommonCommand_lsmaps(float request, entity caller);
+void CommonCommand_lsmaps(int request, entity caller);
 
-void CommonCommand_printmaplist(float request, entity caller);
+void CommonCommand_printmaplist(int request, entity caller);
 
-void CommonCommand_rankings(float request, entity caller);
+void CommonCommand_rankings(int request, entity caller);
 
-void CommonCommand_records(float request, entity caller);
+void CommonCommand_records(int request, entity caller);
 
-void CommonCommand_teamstatus(float request, entity caller);
+void CommonCommand_teamstatus(int request, entity caller);
 
-void CommonCommand_time(float request, entity caller);
+void CommonCommand_time(int request, entity caller);
 
-void CommonCommand_timein(float request, entity caller);
+void CommonCommand_timein(int request, entity caller);
 
-void CommonCommand_timeout(float request, entity caller);
+void CommonCommand_timeout(int request, entity caller);
 
-void CommonCommand_who(float request, entity caller, float argc);
+void CommonCommand_who(int request, entity caller, int argc);
 
 
 // ==================================
@@ -160,7 +160,7 @@ void CommonCommand_macro_help(entity caller)
        FOREACH(COMMON_COMMANDS, true, { print_to(caller, sprintf("  ^2%s^7: %s", it.m_name, it.m_description)); });
 }
 
-float CommonCommand_macro_command(float argc, entity caller, string command)
+float CommonCommand_macro_command(int argc, entity caller, string command)
 {
        string c = strtolower(argv(0));
        FOREACH(COMMON_COMMANDS, it.m_name == c, {
@@ -170,7 +170,7 @@ float CommonCommand_macro_command(float argc, entity caller, string command)
        return false;
 }
 
-float CommonCommand_macro_usage(float argc, entity caller)
+float CommonCommand_macro_usage(int argc, entity caller)
 {
        string c = strtolower(argv(1));
        FOREACH(COMMON_COMMANDS, it.m_name == c, {
index 87bcef82f7124e1f001603129320b0684d46af5f..e3dbf795f60541f9482f4997c42b28b540552837 100644 (file)
@@ -366,7 +366,7 @@ void RadarMap_Think(entity this)
        }
 }
 
-bool RadarMap_Make(float argc)
+bool RadarMap_Make(int argc)
 {
        float i;
 
index ffa82e5c02e09131efb74f5fd150fba0b4e601ec..44bd8fb4bac922794440153d22b1ee0ac9422d13 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 #ifndef RADARMAP
-bool RadarMap_Make(float argc) { LOG_INFO("radarmap is disabled, compile with -DRADARMAP to enable it."); return true; }
+bool RadarMap_Make(int argc) { LOG_INFO("radarmap is disabled, compile with -DRADARMAP to enable it."); return true; }
 #else
 
 // ===========================================
@@ -17,6 +17,6 @@ string doublehex = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D
 // FF is contained twice, to map 256 to FF too
 // removes the need to bound()
 
-bool RadarMap_Make(float argc);
+bool RadarMap_Make(int argc);
 
 #endif
index 1076225d82acaf1e89a00432927c4c95b8593c34..c917874c358f5d345cd740fcffa194033f9f54c7 100644 (file)
@@ -88,7 +88,7 @@ void changematchtime(float delta, float mi, float ma)
 //  Command Sub-Functions
 // =======================
 
-void GameCommand_adminmsg(float request, float argc)
+void GameCommand_adminmsg(int request, int argc)
 {
        switch (request)
        {
@@ -160,7 +160,7 @@ void GameCommand_adminmsg(float request, float argc)
        }
 }
 
-void GameCommand_allready(float request)
+void GameCommand_allready(int request)
 {
        switch (request)
        {
@@ -180,7 +180,7 @@ void GameCommand_allready(float request)
        }
 }
 
-void GameCommand_allspec(float request, float argc)
+void GameCommand_allspec(int request, int argc)
 {
        switch (request)
        {
@@ -209,7 +209,7 @@ void GameCommand_allspec(float request, float argc)
        }
 }
 
-void GameCommand_anticheat(float request, float argc)
+void GameCommand_anticheat(int request, int argc)
 {
        switch (request)
        {
@@ -240,7 +240,7 @@ void GameCommand_anticheat(float request, float argc)
        }
 }
 
-void GameCommand_bbox(float request)
+void GameCommand_bbox(int request)
 {
        switch (request)
        {
@@ -313,7 +313,7 @@ void GameCommand_bbox(float request)
        }
 }
 
-void GameCommand_bot_cmd(float request, float argc, string command)
+void GameCommand_bot_cmd(int request, int argc, string command)
 {
        switch (request)
        {
@@ -445,7 +445,7 @@ void GameCommand_bot_cmd(float request, float argc, string command)
        }
 }
 
-void GameCommand_cointoss(float request, float argc)
+void GameCommand_cointoss(int request, int argc)
 {
        switch (request)
        {
@@ -469,7 +469,7 @@ void GameCommand_cointoss(float request, float argc)
        }
 }
 
-void GameCommand_database(float request, float argc)
+void GameCommand_database(int request, int argc)
 {
        switch (request)
        {
@@ -512,7 +512,7 @@ void GameCommand_database(float request, float argc)
        }
 }
 
-void GameCommand_defer_clear(float request, float argc)
+void GameCommand_defer_clear(int request, int argc)
 {
        switch (request)
        {
@@ -549,14 +549,14 @@ void GameCommand_defer_clear(float request, float argc)
        }
 }
 
-void GameCommand_defer_clear_all(float request)
+void GameCommand_defer_clear_all(int request)
 {
        switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        int n = 0;
-                       float argc;
+                       int argc;
 
                        FOREACH_CLIENT(true, {
                                argc = tokenize_console(strcat("defer_clear ", ftos(etof(it))));
@@ -578,7 +578,7 @@ void GameCommand_defer_clear_all(float request)
        }
 }
 
-void GameCommand_delrec(float request, float argc)  // perhaps merge later with records and printstats and such?
+void GameCommand_delrec(int request, int argc)  // perhaps merge later with records and printstats and such?
 {
        switch (request)
        {
@@ -605,7 +605,7 @@ void GameCommand_delrec(float request, float argc)  // perhaps merge later with
        }
 }
 
-void GameCommand_effectindexdump(float request)
+void GameCommand_effectindexdump(int request)
 {
        switch (request)
        {
@@ -719,7 +719,7 @@ void GameCommand_effectindexdump(float request)
        }
 }
 
-void GameCommand_extendmatchtime(float request)
+void GameCommand_extendmatchtime(int request)
 {
        switch (request)
        {
@@ -740,7 +740,7 @@ void GameCommand_extendmatchtime(float request)
        }
 }
 
-void GameCommand_gametype(float request, float argc)
+void GameCommand_gametype(int request, int argc)
 {
        switch (request)
        {
@@ -790,7 +790,7 @@ void GameCommand_gametype(float request, float argc)
        }
 }
 
-void GameCommand_gettaginfo(float request, float argc)
+void GameCommand_gettaginfo(int request, int argc)
 {
        switch (request)
        {
@@ -855,7 +855,7 @@ void GameCommand_gettaginfo(float request, float argc)
        }
 }
 
-void GameCommand_animbench(float request, float argc)
+void GameCommand_animbench(int request, int argc)
 {
        switch (request)
        {
@@ -914,7 +914,7 @@ void GameCommand_animbench(float request, float argc)
        }
 }
 
-void GameCommand_gotomap(float request, float argc)
+void GameCommand_gotomap(int request, int argc)
 {
        switch (request)
        {
@@ -939,7 +939,7 @@ void GameCommand_gotomap(float request, float argc)
        }
 }
 
-void GameCommand_lockteams(float request)
+void GameCommand_lockteams(int request)
 {
        switch (request)
        {
@@ -968,7 +968,7 @@ void GameCommand_lockteams(float request)
        }
 }
 
-void GameCommand_make_mapinfo(float request)
+void GameCommand_make_mapinfo(int request)
 {
        switch (request)
        {
@@ -994,7 +994,7 @@ void GameCommand_make_mapinfo(float request)
        }
 }
 
-void GameCommand_moveplayer(float request, float argc)
+void GameCommand_moveplayer(int request, int argc)
 {
        switch (request)
        {
@@ -1057,6 +1057,7 @@ void GameCommand_moveplayer(float request, float argc)
 
                                                                // find the team to move the player to
                                                                team_id = Team_ColorToTeam(destination);
+                                                               entity balance;
                                                                if (team_id == client.team)  // already on the destination team
                                                                {
                                                                        // keep the forcing undone
@@ -1065,30 +1066,72 @@ void GameCommand_moveplayer(float request, float argc)
                                                                }
                                                                else if (team_id == 0)  // auto team
                                                                {
-                                                                       CheckAllowedTeams(client);
-                                                                       team_id = Team_NumberToTeam(FindSmallestTeam(client, false));
+                                                                       balance = TeamBalance_CheckAllowedTeams(client);
+                                                                       team_id = Team_IndexToTeam(TeamBalance_FindBestTeam(balance, client, false));
                                                                }
                                                                else
                                                                {
-                                                                       CheckAllowedTeams(client);
+                                                                       balance = TeamBalance_CheckAllowedTeams(client);
                                                                }
                                                                client.team_forced = save;
 
                                                                // Check to see if the destination team is even available
                                                                switch (team_id)
                                                                {
-                                                                       case NUM_TEAM_1: if (c1 == -1) { LOG_INFO("Sorry, can't move player to red team if it doesn't exist."); return; } break;
-                                                                       case NUM_TEAM_2: if (c2 == -1) { LOG_INFO("Sorry, can't move player to blue team if it doesn't exist."); return; } break;
-                                                                       case NUM_TEAM_3: if (c3 == -1) { LOG_INFO("Sorry, can't move player to yellow team if it doesn't exist."); return; } break;
-                                                                       case NUM_TEAM_4: if (c4 == -1) { LOG_INFO("Sorry, can't move player to pink team if it doesn't exist."); return; } break;
-
-                                                                       default: LOG_INFO("Sorry, can't move player here if team ", destination, " doesn't exist.");
+                                                                       case NUM_TEAM_1:
+                                                                       {
+                                                                               if (!TeamBalance_IsTeamAllowed(balance, 1))
+                                                                               {
+                                                                                       LOG_INFO("Sorry, can't move player to red team if it doesn't exist.");
+                                                                                       TeamBalance_Destroy(balance);
+                                                                                       return;
+                                                                               }
+                                                                               TeamBalance_Destroy(balance);
+                                                                               break;
+                                                                       }
+                                                                       case NUM_TEAM_2:
+                                                                       {
+                                                                               if (!TeamBalance_IsTeamAllowed(balance, 2))
+                                                                               {
+                                                                                       LOG_INFO("Sorry, can't move player to blue team if it doesn't exist.");
+                                                                                       TeamBalance_Destroy(balance);
+                                                                                       return;
+                                                                               }
+                                                                               TeamBalance_Destroy(balance);
+                                                                               break;
+                                                                       }
+                                                                       case NUM_TEAM_3:
+                                                                       {
+                                                                               if (!TeamBalance_IsTeamAllowed(balance, 3))
+                                                                               {
+                                                                                       LOG_INFO("Sorry, can't move player to yellow team if it doesn't exist.");
+                                                                                       TeamBalance_Destroy(balance);
+                                                                                       return;
+                                                                               }
+                                                                               TeamBalance_Destroy(balance);
+                                                                               break;
+                                                                       }
+                                                                       case NUM_TEAM_4:
+                                                                       {
+                                                                               if (!TeamBalance_IsTeamAllowed(balance, 4))
+                                                                               {
+                                                                                       LOG_INFO("Sorry, can't move player to pink team if it doesn't exist.");
+                                                                                       TeamBalance_Destroy(balance);
+                                                                                       return;
+                                                                               }
+                                                                               TeamBalance_Destroy(balance);
+                                                                               break;
+                                                                       }
+                                                                       default:
+                                                                       {
+                                                                               LOG_INFO("Sorry, can't move player here if team ", destination, " doesn't exist.");
                                                                                return;
+                                                                       }
                                                                }
 
                                                                // If so, lets continue and finally move the player
                                                                client.team_forced = 0;
-                                                               if (MoveToTeam(client, team_id, 6))
+                                                               if (MoveToTeam(client, Team_TeamToIndex(team_id), 6))
                                                                {
                                                                        successful = strcat(successful, (successful ? ", " : ""), playername(client, false));
                                                                        LOG_INFO("Player ", ftos(GetFilteredNumber(t)), " (", playername(client, false), ") has been moved to the ", Team_ColoredFullName(team_id), "^7.");
@@ -1136,7 +1179,7 @@ void GameCommand_moveplayer(float request, float argc)
        }
 }
 
-void GameCommand_nospectators(float request)
+void GameCommand_nospectators(int request)
 {
        switch (request)
        {
@@ -1165,7 +1208,7 @@ void GameCommand_nospectators(float request)
        }
 }
 
-void GameCommand_printstats(float request)
+void GameCommand_printstats(int request)
 {
        switch (request)
        {
@@ -1186,7 +1229,7 @@ void GameCommand_printstats(float request)
        }
 }
 
-void GameCommand_radarmap(float request, float argc)
+void GameCommand_radarmap(int request, int argc)
 {
        switch (request)
        {
@@ -1208,7 +1251,7 @@ void GameCommand_radarmap(float request, float argc)
        }
 }
 
-void GameCommand_reducematchtime(float request)
+void GameCommand_reducematchtime(int request)
 {
        switch (request)
        {
@@ -1229,7 +1272,7 @@ void GameCommand_reducematchtime(float request)
        }
 }
 
-void GameCommand_setbots(float request, float argc)
+void GameCommand_setbots(int request, int argc)
 {
        switch (request)
        {
@@ -1256,7 +1299,7 @@ void GameCommand_setbots(float request, float argc)
        }
 }
 
-void GameCommand_shuffleteams(float request)
+void GameCommand_shuffleteams(int request)
 {
        switch (request)
        {
@@ -1279,16 +1322,23 @@ void GameCommand_shuffleteams(float request)
                        });
 
                        int number_of_teams = 0;
-                       CheckAllowedTeams(NULL);
-                       if (c1 >= 0) number_of_teams = max(1, number_of_teams);
-                       if (c2 >= 0) number_of_teams = max(2, number_of_teams);
-                       if (c3 >= 0) number_of_teams = max(3, number_of_teams);
-                       if (c4 >= 0) number_of_teams = max(4, number_of_teams);
+                       entity balance = TeamBalance_CheckAllowedTeams(NULL);
+                       for (int i = 1; i <= NUM_TEAMS; ++i)
+                       {
+                               if (TeamBalance_IsTeamAllowed(balance, i))
+                               {
+                                       number_of_teams = max(i, number_of_teams);
+                               }
+                       }
+                       TeamBalance_Destroy(balance);
 
                        int team_index = 0;
                        FOREACH_CLIENT_RANDOM(IS_PLAYER(it) || it.caplayer, {
-                               int target_team_number = Team_NumberToTeam(team_index + 1);
-                               if (it.team != target_team_number) MoveToTeam(it, target_team_number, 6);
+                               int target_team_index = team_index + 1;
+                               if (Entity_GetTeamIndex(it) != target_team_index)
+                               {
+                                       MoveToTeam(it, target_team_index, 6);
+                               }
                                team_index = (team_index + 1) % number_of_teams;
                        });
 
@@ -1307,7 +1357,7 @@ void GameCommand_shuffleteams(float request)
        }
 }
 
-void GameCommand_stuffto(float request, float argc)
+void GameCommand_stuffto(int request, int argc)
 {
        // This... is a fairly dangerous and powerful command... - It allows any arguments to be sent to a client via rcon.
        // Because of this, it is disabled by default and must be enabled by the server owner when doing compilation. That way,
@@ -1356,7 +1406,7 @@ void GameCommand_stuffto(float request, float argc)
 #endif
 }
 
-void GameCommand_trace(float request, float argc)
+void GameCommand_trace(int request, int argc)
 {
        switch (request)
        {
@@ -1532,7 +1582,7 @@ void GameCommand_trace(float request, float argc)
        }
 }
 
-void GameCommand_unlockteams(float request)
+void GameCommand_unlockteams(int request)
 {
        switch (request)
        {
@@ -1561,7 +1611,7 @@ void GameCommand_unlockteams(float request)
        }
 }
 
-void GameCommand_warp(float request, float argc)
+void GameCommand_warp(int request, int argc)
 {
        switch (request)
        {
@@ -1600,7 +1650,7 @@ void GameCommand_warp(float request, float argc)
 
 /* use this when creating a new command, making sure to place it in alphabetical order... also,
 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
-void GameCommand_(float request)
+void GameCommand_(int request)
 {
     switch(request)
     {
@@ -1663,7 +1713,7 @@ void GameCommand_macro_help()
        FOREACH(SERVER_COMMANDS, true, { LOG_INFOF("  ^2%s^7: %s", it.m_name, it.m_description); });
 }
 
-float GameCommand_macro_command(float argc, string command)
+float GameCommand_macro_command(int argc, string command)
 {
        string c = strtolower(argv(0));
        FOREACH(SERVER_COMMANDS, it.m_name == c, {
@@ -1673,7 +1723,7 @@ float GameCommand_macro_command(float argc, string command)
        return false;
 }
 
-float GameCommand_macro_usage(float argc)
+float GameCommand_macro_usage(int argc)
 {
        string c = strtolower(argv(1));
        FOREACH(SERVER_COMMANDS, it.m_name == c, {
@@ -1696,7 +1746,7 @@ void GameCommand_macro_write_aliases(float fh)
 
 void GameCommand(string command)
 {
-       float argc = tokenize_console(command);
+       int argc = tokenize_console(command);
 
        // Guide for working with argc arguments by example:
        // argc:   1    - 2      - 3     - 4
index 5f034f12f88534e9f644eeba88bed1351246ecb2..6d9b4d76e115b8189700c35fb0201d6369b99bca 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "../g_damage.qh"
 #include "../g_world.qh"
+#include "../teamplay.qh"
 #include "../race.qh"
 #include "../round_handler.qh"
 #include "../scores.qh"
@@ -514,7 +515,7 @@ float Votecommand_check_assignment(entity caller, float assignment)
        return false;
 }
 
-string VoteCommand_extractcommand(string input, float startpos, float argc)
+string VoteCommand_extractcommand(string input, float startpos, int argc)
 {
        string output;
 
@@ -571,7 +572,7 @@ string ValidateMap(string validated_map, entity caller)
        return validated_map;
 }
 
-float VoteCommand_checkargs(float startpos, float argc)
+float VoteCommand_checkargs(float startpos, int argc)
 {
        float p, q, check, minargs;
        string cvarname = strcat("sv_vote_command_restriction_", argv(startpos));
@@ -645,7 +646,7 @@ float VoteCommand_checkargs(float startpos, float argc)
        return true;
 }
 
-int VoteCommand_parse(entity caller, string vote_command, string vote_list, float startpos, float argc)
+int VoteCommand_parse(entity caller, string vote_command, string vote_list, float startpos, int argc)
 {
        string first_command = argv(startpos);
        int missing_chars = argv_start_index(startpos);
@@ -730,7 +731,7 @@ int VoteCommand_parse(entity caller, string vote_command, string vote_list, floa
 //  Command Sub-Functions
 // =======================
 
-void VoteCommand_abstain(float request, entity caller)  // CLIENT ONLY
+void VoteCommand_abstain(int request, entity caller)  // CLIENT ONLY
 {
        switch (request)
        {
@@ -762,7 +763,7 @@ void VoteCommand_abstain(float request, entity caller)  // CLIENT ONLY
        }
 }
 
-void VoteCommand_call(float request, entity caller, float argc, string vote_command)  // BOTH
+void VoteCommand_call(int request, entity caller, int argc, string vote_command)  // BOTH
 {
        switch (request)
        {
@@ -849,7 +850,7 @@ void VoteCommand_call(float request, entity caller, float argc, string vote_comm
        }
 }
 
-void VoteCommand_master(float request, entity caller, float argc, string vote_command)  // CLIENT ONLY
+void VoteCommand_master(int request, entity caller, int argc, string vote_command)  // CLIENT ONLY
 {
        switch (request)
        {
@@ -964,7 +965,7 @@ void VoteCommand_master(float request, entity caller, float argc, string vote_co
        }
 }
 
-void VoteCommand_no(float request, entity caller)  // CLIENT ONLY
+void VoteCommand_no(int request, entity caller)  // CLIENT ONLY
 {
        switch (request)
        {
@@ -1002,7 +1003,7 @@ void VoteCommand_no(float request, entity caller)  // CLIENT ONLY
        }
 }
 
-void VoteCommand_status(float request, entity caller)  // BOTH
+void VoteCommand_status(int request, entity caller)  // BOTH
 {
        switch (request)
        {
@@ -1024,7 +1025,7 @@ void VoteCommand_status(float request, entity caller)  // BOTH
        }
 }
 
-void VoteCommand_stop(float request, entity caller)  // BOTH
+void VoteCommand_stop(int request, entity caller)  // BOTH
 {
        switch (request)
        {
@@ -1046,7 +1047,7 @@ void VoteCommand_stop(float request, entity caller)  // BOTH
        }
 }
 
-void VoteCommand_yes(float request, entity caller)  // CLIENT ONLY
+void VoteCommand_yes(int request, entity caller)  // CLIENT ONLY
 {
        switch (request)
        {
@@ -1081,7 +1082,7 @@ void VoteCommand_yes(float request, entity caller)  // CLIENT ONLY
 
 /* use this when creating a new command, making sure to place it in alphabetical order... also,
 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
-void VoteCommand_(float request)
+void VoteCommand_(int request)
 {
     switch(request)
     {
@@ -1119,7 +1120,7 @@ void VoteCommand_(float request)
        VOTE_COMMAND("yes", VoteCommand_yes(request, caller), "Select yes in current vote", VC_ASGNMNT_CLIENTONLY) \
        /* nothing */
 
-void VoteCommand_macro_help(entity caller, float argc)
+void VoteCommand_macro_help(entity caller, int argc)
 {
        string command_origin = GetCommandPrefix(caller);
 
@@ -1152,7 +1153,7 @@ void VoteCommand_macro_help(entity caller, float argc)
        }
 }
 
-float VoteCommand_macro_command(entity caller, float argc, string vote_command)
+float VoteCommand_macro_command(entity caller, int argc, string vote_command)
 {
        #define VOTE_COMMAND(name, function, description, assignment) \
                { if (Votecommand_check_assignment(caller, assignment)) { if (name == strtolower(argv(1))) { function; return true; } } }
@@ -1168,7 +1169,7 @@ float VoteCommand_macro_command(entity caller, float argc, string vote_command)
 //  Main function handling vote commands
 // ======================================
 
-void VoteCommand(float request, entity caller, float argc, string vote_command)
+void VoteCommand(int request, entity caller, int argc, string vote_command)
 {
        // Guide for working with argc arguments by example:
        // argc:   1    - 2      - 3     - 4
index d5c3bc0ad0e937d9569d1ec95cc539cd09c78897..988e91bbce615648873186adf6fb5306d4641c54 100644 (file)
@@ -41,7 +41,7 @@ string vote_parsed_display; // visual string which is fixed after being parsed
 // allow functions to be used in other code like g_world.qc and teamplay.qc
 void VoteThink();
 void VoteReset();
-void VoteCommand(float request, entity caller, float argc, string vote_command);
+void VoteCommand(int request, entity caller, int argc, string vote_command);
 
 // warmup and nagger stuff
 const float RESTART_COUNTDOWN = 10;
index e830fe6c4fe8ed7caf27748935faa8d41cdd4967..c80da0af3772cf40ddd744cf1c471f0268702e23 100644 (file)
@@ -15,4 +15,4 @@ SPAWNFUNC_ITEM(item_spikes, ITEM_Bullets)
 //spawnfunc(item_armor1) {spawnfunc_item_armor_medium(this);}  // FIXME: in Quake this is green armor, in Xonotic maps it is an armor shard
 SPAWNFUNC_ITEM(item_armor2, ITEM_ArmorMega)
 SPAWNFUNC_ITEM(item_armorInv, ITEM_ArmorMega) // TODO: make sure we actually want this
-spawnfunc(item_health) {if (this.spawnflags & 2) StartItem(this, ITEM_HealthMega);else StartItem(this, ITEM_HealthMedium);}
+SPAWNFUNC_ITEM_COND(item_health, (this.spawnflags & 2), ITEM_HealthMega, ITEM_HealthMedium)
index 4c23aaeb3b956f6706b8dcea57db48f1c4231f01..3aed06ee41a22b66d9cb69e1357628e91c90d480 100644 (file)
@@ -25,9 +25,7 @@ float currentbots;
 float bots_would_leave;
 
 void UpdateFrags(entity player, int f);
-.float totalfrags;
-
-float team1_score, team2_score, team3_score, team4_score;
+.int totalfrags;
 
 // flag set on worldspawn so that the code knows if it is dedicated or not
 float server_is_dedicated;
@@ -43,7 +41,7 @@ float server_is_dedicated;
 
 //.float       worldtype;
 // Needed for dynamic clientwalls
-.float inactive; // Clientwall disappears when inactive
+.bool inactive; // Clientwall disappears when inactive
 .float alpha_max, alpha_min;
 .float fade_start, fade_end, fade_vertical_offset;
 .float default_solid; // Variable to store default .solid for clientwalls
@@ -215,7 +213,7 @@ float assault_attacker_team;
 float ServerProgsDB;
 float TemporaryDB;
 
-.float team_saved;
+.int team_saved;
 
 bool some_spawn_has_been_used;
 int have_team_spawns; // 0 = no team spawns requested, -1 = team spawns requested but none found, 1 = team spawns requested and found
@@ -231,8 +229,6 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
 // WEAPONTODO
 #define DMG_NOWEP (weaponentities[0])
 
-float lockteams;
-
 float sv_maxidle;
 float sv_maxidle_spectatorsareidle;
 int sv_maxidle_slots;
@@ -312,9 +308,9 @@ float client_cefc_accumulatortime;
 
 .float weapon_load[Weapons_MAX];
 .int ammo_none; // used by the reloading system, must always be 0
-.float clip_load;
-.float old_clip_load;
-.float clip_size;
+.int clip_load;
+.int old_clip_load;
+.int clip_size;
 
 .int minelayer_mines;
 .float vortex_charge;
@@ -331,9 +327,9 @@ float client_cefc_accumulatortime;
 // when doing this, hagar can go through clones
 // #define PROJECTILE_MAKETRIGGER(e) (e).solid = SOLID_BBOX
 
-.float spectatee_status;
-.float zoomstate;
-.float restriction;
+.int spectatee_status;
+.bool zoomstate;
+.int restriction;
 
 .entity clientdata;
 .entity personal;
@@ -343,24 +339,24 @@ string deathmessage;
 .bool just_joined;
 
 .float cvar_cl_weaponimpulsemode;
-.float selectweapon; // last selected weapon of the player
+.int selectweapon; // last selected weapon of the player
 
 .float ballistics_density; // wall piercing factor, larger = bullet can pass through more
 
-const float ACTIVE_NOT                 = 0;
-const float ACTIVE_ACTIVE      = 1;
-const float ACTIVE_IDLE        = 2;
-const float ACTIVE_BUSY        = 2;
-const float ACTIVE_TOGGLE      = 3;
-.float active;
+const int ACTIVE_NOT           = 0;
+const int ACTIVE_ACTIVE        = 1;
+const int ACTIVE_IDLE          = 2;
+const int ACTIVE_BUSY          = 2;
+const int ACTIVE_TOGGLE        = 3;
+.int active;
 .void (entity this, int act_state) setactive;
 .entity realowner;
 
 //float serverflags;
 
-.float team_forced; // can be a team number to force a team, or 0 for default action, or -1 for forced spectator
+.int team_forced; // can be a team number to force a team, or 0 for default action, or -1 for forced spectator
 
-.float player_blocked;
+.bool player_blocked;
 
 .float revival_time; // time at which player was last revived
 .float revive_speed; // NOTE: multiplier (anything above 1 is instaheal)
@@ -380,7 +376,7 @@ USING(spawn_evalfunc_t, vector(entity this, entity player, entity spot, vector c
 
 string modname;
 
-.float missile_flags;
+.int missile_flags;
 const int MIF_SPLASH = BIT(1);
 const int MIF_ARC = BIT(2);
 const int MIF_PROXY = BIT(3);
index cc0c71be5d56e32a1ad721a1e8fe1a9726645a43..a25ae5bec9f878d9ba5feca5a6bb2f7e7c55bae6 100644 (file)
@@ -35,7 +35,7 @@ void UpdateFrags(entity player, int f)
        GameRules_scoring_add_team(player, SCORE, f);
 }
 
-void GiveFrags (entity attacker, entity targ, float f, int deathtype, .entity weaponentity)
+void GiveFrags(entity attacker, entity targ, float f, int deathtype, .entity weaponentity)
 {
        // TODO route through PlayerScores instead
        if(game_stopped) return;
@@ -477,9 +477,9 @@ void Ice_Think(entity this)
        this.nextthink = time;
 }
 
-void Freeze (entity targ, float revivespeed, float frozen_type, float show_waypoint)
+void Freeze(entity targ, float revivespeed, int frozen_type, bool show_waypoint)
 {
-       if(!IS_PLAYER(targ) && !IS_MONSTER(targ)) // only specified entities can be freezed
+       if(!IS_PLAYER(targ) && !IS_MONSTER(targ)) // TODO: only specified entities can be freezed
                return;
 
        if(STAT(FROZEN, targ))
@@ -524,11 +524,11 @@ void Freeze (entity targ, float revivespeed, float frozen_type, float show_waypo
        });
 
        // add waypoint
-       if(show_waypoint)
+       if(MUTATOR_CALLHOOK(Freeze, targ, revivespeed, frozen_type) || show_waypoint)
                WaypointSprite_Spawn(WP_Frozen, 0, 0, targ, '0 0 64', NULL, targ.team, targ, waypointsprite_attached, true, RADARICON_WAYPOINT);
 }
 
-void Unfreeze (entity targ)
+void Unfreeze(entity targ)
 {
        if(!STAT(FROZEN, targ))
                return;
@@ -562,9 +562,11 @@ void Unfreeze (entity targ)
        if(targ.iceblock)
                delete(targ.iceblock);
        targ.iceblock = NULL;
+
+       MUTATOR_CALLHOOK(Unfreeze, targ);
 }
 
-void Damage (entity targ, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+void Damage(entity targ, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
        float complainteamdamage = 0;
        float mirrordamage = 0;
@@ -1038,9 +1040,9 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in
                                                }
 
                                                if(targ == directhitentity || DEATH_ISSPECIAL(deathtype))
-                                                       Damage (targ, inflictor, attacker, finaldmg, deathtype, weaponentity, nearest, force);
+                                                       Damage(targ, inflictor, attacker, finaldmg, deathtype, weaponentity, nearest, force);
                                                else
-                                                       Damage (targ, inflictor, attacker, finaldmg, deathtype | HITTYPE_SPLASH, weaponentity, nearest, force);
+                                                       Damage(targ, inflictor, attacker, finaldmg, deathtype | HITTYPE_SPLASH, weaponentity, nearest, force);
                                        }
                                }
                        }
@@ -1056,9 +1058,9 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in
        return total_damage_to_creatures;
 }
 
-float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity)
+float RadiusDamage(entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity)
 {
-       return RadiusDamageForSource (inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, cantbe, mustbe, false, forceintensity, deathtype, weaponentity, directhitentity);
+       return RadiusDamageForSource(inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, cantbe, mustbe, false, forceintensity, deathtype, weaponentity, directhitentity);
 }
 
 bool Heal(entity targ, entity inflictor, float amount, float limit)
index 88fbf134422134492c3ee1756549d4b2131fa8ab..617eca1985108e4ca82fc2b31167a8b23c69ff9b 100644 (file)
@@ -49,7 +49,7 @@ float damage_gooddamage;
 .float teamkill_soundtime;
 .entity teamkill_soundsource;
 .entity pusher;
-.float istypefrag;
+.bool istypefrag;
 .float taunt_soundtime;
 
 float IsFlying(entity a);
@@ -83,7 +83,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
 
 void Ice_Think(entity this);
 
-void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypoint);
+void Freeze(entity targ, float freeze_time, int frozen_type, bool show_waypoint);
 
 void Unfreeze (entity targ);
 
index 26a4cfb08685c3d16f58f8acd5416d693ed65b18..038936ee49282bff375700dd76159197aea86d8f 100644 (file)
@@ -16,6 +16,7 @@
 #include <server/mutators/_mod.qh>
 #include "race.qh"
 #include "scores.qh"
+#include "scores_rules.qh"
 #include "teamplay.qh"
 #include "weapons/weaponstats.qh"
 #include "../common/constants.qh"
@@ -578,6 +579,58 @@ STATIC_INIT_EARLY(maxclients)
        }
 }
 
+void default_delayedinit(entity this)
+{
+       if(!scores_initialized)
+               ScoreRules_generic();
+}
+
+void InitGameplayMode()
+{
+       VoteReset();
+
+       // find out good world mins/maxs bounds, either the static bounds found by looking for solid, or the mapinfo specified bounds
+       get_mi_min_max(1);
+       // assign reflectively to avoid "assignment to world" warning
+       int done = 0; for (int i = 0, n = numentityfields(); i < n; ++i) {
+           string k = entityfieldname(i); vector v = (k == "mins") ? mi_min : (k == "maxs") ? mi_max : '0 0 0';
+           if (v) {
+            putentityfieldstring(i, world, sprintf("%v", v));
+            if (++done == 2) break;
+        }
+       }
+       // currently, NetRadiant's limit is 131072 qu for each side
+       // distance from one corner of a 131072qu cube to the opposite corner is approx. 227023 qu
+       // set the distance according to map size but don't go over the limit to avoid issues with float precision
+       // in case somebody makes extremely large maps
+       max_shot_distance = min(230000, vlen(world.maxs - world.mins));
+
+       MapInfo_LoadMapSettings(mapname);
+       GameRules_teams(false);
+
+       if (!cvar_value_issafe(world.fog))
+       {
+               LOG_INFO("The current map contains a potentially harmful fog setting, ignored");
+               world.fog = string_null;
+       }
+       if(MapInfo_Map_fog != "")
+               if(MapInfo_Map_fog == "none")
+                       world.fog = string_null;
+               else
+                       world.fog = strzone(MapInfo_Map_fog);
+       clientstuff = strzone(MapInfo_Map_clientstuff);
+
+       MapInfo_ClearTemps();
+
+       gamemode_name = MapInfo_Type_ToText(MapInfo_LoadedGametype);
+
+       cache_mutatormsg = strzone("");
+       cache_lastmutatormsg = strzone("");
+
+       InitializeEntity(NULL, default_delayedinit, INITPRIO_GAMETYPE_FALLBACK);
+}
+
+void Map_MarkAsRecent(string m);
 float world_already_spawned;
 spawnfunc(worldspawn)
 {
@@ -1646,10 +1699,11 @@ float WinningCondition_Scores(float limit, float leadlimit)
 
        if(teamplay)
        {
-               team1_score = TeamScore_GetCompareValue(NUM_TEAM_1);
-               team2_score = TeamScore_GetCompareValue(NUM_TEAM_2);
-               team3_score = TeamScore_GetCompareValue(NUM_TEAM_3);
-               team4_score = TeamScore_GetCompareValue(NUM_TEAM_4);
+               for (int i = 1; i < 5; ++i)
+               {
+                       Team_SetTeamScore(Team_GetTeamFromIndex(i),
+                               TeamScore_GetCompareValue(Team_IndexToTeam(i)));
+               }
        }
 
        ClearWinners();
@@ -1719,30 +1773,32 @@ float WinningCondition_RanOutOfSpawns()
        if(!some_spawn_has_been_used)
                return WINNING_NO;
 
-       team1_score = team2_score = team3_score = team4_score = 0;
-
-       FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
-               switch(it.team)
+       for (int i = 1; i < 5; ++i)
+       {
+               Team_SetTeamScore(Team_GetTeamFromIndex(i), 0);
+       }
+       
+       FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it),
+       {
+               if (Team_IsValidTeam(it.team))
                {
-                       case NUM_TEAM_1: team1_score = 1; break;
-                       case NUM_TEAM_2: team2_score = 1; break;
-                       case NUM_TEAM_3: team3_score = 1; break;
-                       case NUM_TEAM_4: team4_score = 1; break;
+                       Team_SetTeamScore(Team_GetTeam(it.team), 1);
                }
        });
 
        IL_EACH(g_spawnpoints, true,
        {
-               switch(it.team)
+               if (Team_IsValidTeam(it.team))
                {
-                       case NUM_TEAM_1: team1_score = 1; break;
-                       case NUM_TEAM_2: team2_score = 1; break;
-                       case NUM_TEAM_3: team3_score = 1; break;
-                       case NUM_TEAM_4: team4_score = 1; break;
+                       Team_SetTeamScore(Team_GetTeam(it.team), 1);
                }
        });
 
        ClearWinners();
+       float team1_score = Team_GetTeamScore(Team_GetTeamFromIndex(1));
+       float team2_score = Team_GetTeamScore(Team_GetTeamFromIndex(2));
+       float team3_score = Team_GetTeamScore(Team_GetTeamFromIndex(3));
+       float team4_score = Team_GetTeamScore(Team_GetTeamFromIndex(4));
        if(team1_score + team2_score + team3_score + team4_score == 0)
        {
                checkrules_equality = true;
@@ -1752,20 +1808,28 @@ float WinningCondition_RanOutOfSpawns()
        {
                float t, i;
                if(team1_score)
-                       t = NUM_TEAM_1;
+                       t = 1;
                else if(team2_score)
-                       t = NUM_TEAM_2;
+                       t = 2;
                else if(team3_score)
-                       t = NUM_TEAM_3;
+                       t = 3;
                else // if(team4_score)
-                       t = NUM_TEAM_4;
-               CheckAllowedTeams(NULL);
+                       t = 4;
+               entity balance = TeamBalance_CheckAllowedTeams(NULL);
                for(i = 0; i < MAX_TEAMSCORE; ++i)
                {
-                       if(t != NUM_TEAM_1) if(c1 >= 0) TeamScore_AddToTeam(NUM_TEAM_1, i, -1000);
-                       if(t != NUM_TEAM_2) if(c2 >= 0) TeamScore_AddToTeam(NUM_TEAM_2, i, -1000);
-                       if(t != NUM_TEAM_3) if(c3 >= 0) TeamScore_AddToTeam(NUM_TEAM_3, i, -1000);
-                       if(t != NUM_TEAM_4) if(c4 >= 0) TeamScore_AddToTeam(NUM_TEAM_4, i, -1000);
+                       for (int j = 1; j <= NUM_TEAMS; ++j)
+                       {
+                               if (t == j)
+                               {
+                                       continue;
+                               }
+                               if (!TeamBalance_IsTeamAllowed(balance, j))
+                               {
+                                       continue;
+                               }
+                               TeamScore_AddToTeam(Team_IndexToTeam(j), i, -1000);
+                       }
                }
 
                AddWinners(team, t);
index c0c35589a865f476ea08d006f5f43c2ab7996ac6..da950f18575e28a410fbed9955b90a0a5ced4ed7 100644 (file)
@@ -5,6 +5,9 @@ float checkrules_suddendeathwarning;
 float checkrules_suddendeathend;
 float checkrules_overtimesadded; //how many overtimes have been already added
 
+string cache_mutatormsg;
+string cache_lastmutatormsg;
+
 const int WINNING_NO = 0; // no winner, but time limits may terminate the game
 const int WINNING_YES = 1; // winner found
 const int WINNING_NEVER = 2; // no winner, enter overtime if time limit is reached
index 2c0af1c8f2ac12ab4d214bfc84e51dbc94388158..7b1f69384461b5d6f3c95e2e8c8054e24562279c 100644 (file)
@@ -197,7 +197,7 @@ LABEL(skip)
 
 void OnlineBanList_Think(entity this)
 {
-       float argc;
+       int argc;
        string uri;
        float i, n;
 
index 319b6f16ff7e3c7c333d8fb3a67e2b360eefbde8..7ed094cc3a616f6f4b91f0bbe5314e79273cf292 100644 (file)
@@ -40,29 +40,38 @@ void crosshair_trace(entity pl)
 {
        traceline_antilag(pl, CS(pl).cursor_trace_start, CS(pl).cursor_trace_start + normalize(CS(pl).cursor_trace_endpos - CS(pl).cursor_trace_start) * max_shot_distance, MOVE_NORMAL, pl, ANTILAG_LATENCY(pl));
 }
-.bool ctrace_solidchanged;
+
 void crosshair_trace_plusvisibletriggers(entity pl)
+{
+       crosshair_trace_plusvisibletriggers__is_wz(pl, false);
+}
+
+void WarpZone_crosshair_trace_plusvisibletriggers(entity pl)
+{
+       crosshair_trace_plusvisibletriggers__is_wz(pl, true);
+}
+
+void crosshair_trace_plusvisibletriggers__is_wz(entity pl, bool is_wz)
 {
        FOREACH_ENTITY_FLOAT(solid, SOLID_TRIGGER,
        {
                if(it.model != "")
                {
                        it.solid = SOLID_BSP;
-                       it.ctrace_solidchanged = true;
                        IL_PUSH(g_ctrace_changed, it);
                }
        });
 
-       crosshair_trace(pl);
+       if (is_wz)
+               WarpZone_crosshair_trace(pl);
+       else
+               crosshair_trace(pl);
 
-       IL_EACH(g_ctrace_changed, it.ctrace_solidchanged,
-       {
-               it.solid = SOLID_TRIGGER;
-               it.ctrace_solidchanged = false;
-       });
+       IL_EACH(g_ctrace_changed, true, { it.solid = SOLID_TRIGGER; });
 
        IL_CLEAR(g_ctrace_changed);
 }
+
 void WarpZone_crosshair_trace(entity pl)
 {
        WarpZone_traceline_antilag(pl, CS(pl).cursor_trace_start, CS(pl).cursor_trace_start + normalize(CS(pl).cursor_trace_endpos - CS(pl).cursor_trace_start) * max_shot_distance, MOVE_NORMAL, pl, ANTILAG_LATENCY(pl));
@@ -223,16 +232,13 @@ string formatmessage(entity this, string msg)
 {
        float p, p1, p2;
        float n;
-       vector cursor;
-       entity cursor_ent;
+       vector cursor = '0 0 0';
+       entity cursor_ent = NULL;
        string escape;
        string replacement;
        p = 0;
        n = 7;
-
-       WarpZone_crosshair_trace(this);
-       cursor = trace_endpos;
-       cursor_ent = trace_ent;
+       bool traced = false;
 
        MUTATOR_CALLHOOK(PreFormatMessage, this, msg);
        msg = M_ARGV(1, string);
@@ -256,6 +262,14 @@ string formatmessage(entity this, string msg)
                if (p < 0)
                        break;
 
+               if(!traced)
+               {
+                       WarpZone_crosshair_trace_plusvisibletriggers(this);
+                       cursor = trace_endpos;
+                       cursor_ent = trace_ent;
+                       traced = true;
+               }
+
                replacement = substring(msg, p, 2);
                escape = substring(msg, p + 1, 1);
 
@@ -875,7 +889,7 @@ void remove_safely(entity e)
     builtin_remove(e);
 }
 
-void InitializeEntity(entity e, void(entity this) func, float order)
+void InitializeEntity(entity e, void(entity this) func, int order)
 {
     entity prev, cur;
 
index 1455054d2c5cad597ec87e84412d45b74ea6dc00..ff62cd1674b3487185903df618d3198459817beb 100644 (file)
@@ -62,6 +62,8 @@ void attach_sameorigin(entity e, entity to, string tag);
 void crosshair_trace(entity pl);
 
 void crosshair_trace_plusvisibletriggers(entity pl);
+void WarpZone_crosshair_trace_plusvisibletriggers(entity pl);
+void crosshair_trace_plusvisibletriggers__is_wz(entity pl, bool is_wz);
 
 void detach_sameorigin(entity e);
 
@@ -324,17 +326,17 @@ void readlevelcvars()
 
 //#NO AUTOCVARS END
 
-const float INITPRIO_FIRST                             = 0;
-const float INITPRIO_GAMETYPE                  = 0;
-const float INITPRIO_GAMETYPE_FALLBACK         = 1;
-const float INITPRIO_FINDTARGET                = 10;
-const float INITPRIO_DROPTOFLOOR               = 20;
-const float INITPRIO_SETLOCATION               = 90;
-const float INITPRIO_LINKDOORS                         = 91;
-const float INITPRIO_LAST                              = 99;
+const int INITPRIO_FIRST               = 0;
+const int INITPRIO_GAMETYPE            = 0;
+const int INITPRIO_GAMETYPE_FALLBACK   = 1;
+const int INITPRIO_FINDTARGET          = 10;
+const int INITPRIO_DROPTOFLOOR                 = 20;
+const int INITPRIO_SETLOCATION                 = 90;
+const int INITPRIO_LINKDOORS           = 91;
+const int INITPRIO_LAST                = 99;
 
 .void(entity this) initialize_entity;
-.float initialize_entity_order;
+.int initialize_entity_order;
 .entity initialize_entity_next;
 entity initialize_entity_first;
 
@@ -342,8 +344,8 @@ entity initialize_entity_first;
 
 
 
-float sound_allowed(float dest, entity e);
-void InitializeEntity(entity e, void(entity this) func, float order);
+bool sound_allowed(int dest, entity e);
+void InitializeEntity(entity e, void(entity this) func, int order);
 
 IntrusiveList g_ctrace_changed;
 STATIC_INIT(g_ctrace_changed) { g_ctrace_changed = IL_NEW(); }
index de21a59035a5d4d913ab3ba33aa9b2e1ffbbef14..58e9ca127dabb4fb3183616f7815885fcfafa861 100644 (file)
@@ -137,40 +137,51 @@ MUTATOR_HOOKABLE(GiveFragsForKill, EV_GiveFragsForKill);
 /** called when the match ends */
 MUTATOR_HOOKABLE(MatchEnd, EV_NO_ARGS);
 
-/** allows adjusting allowed teams */
-#define EV_CheckAllowedTeams(i, o) \
+/** Allows adjusting allowed teams. Return true to use the bitmask value and set
+ * non-empty string to use team entity name. Both behaviors can be active at the
+ * same time and will stack allowed teams.
+ */
+#define EV_TeamBalance_CheckAllowedTeams(i, o) \
     /** mask of teams      */ i(float, MUTATOR_ARGV_0_float) \
     /**/                      o(float, MUTATOR_ARGV_0_float) \
     /** team entity name   */ i(string, MUTATOR_ARGV_1_string) \
     /**/                      o(string, MUTATOR_ARGV_1_string) \
     /** player checked     */ i(entity, MUTATOR_ARGV_2_entity) \
     /**/
-MUTATOR_HOOKABLE(CheckAllowedTeams, EV_CheckAllowedTeams);
+MUTATOR_HOOKABLE(TeamBalance_CheckAllowedTeams,
+       EV_TeamBalance_CheckAllowedTeams);
 
 /** return true to manually override team counts */
-MUTATOR_HOOKABLE(GetTeamCounts, EV_NO_ARGS);
+MUTATOR_HOOKABLE(TeamBalance_GetTeamCounts, EV_NO_ARGS);
 
-/** allow overriding of team counts */
-#define EV_GetTeamCount(i, o) \
-    /** team to count                   */ i(float, MUTATOR_ARGV_0_float) \
+/** allows overriding of team counts */
+#define EV_TeamBalance_GetTeamCount(i, o) \
+    /** team index to count             */ i(float, MUTATOR_ARGV_0_float) \
     /** player to ignore                */ i(entity, MUTATOR_ARGV_1_entity) \
-    /** number of players in a team     */ i(float, MUTATOR_ARGV_2_float) \
-    /**/                                   o(float, MUTATOR_ARGV_2_float) \
-    /** number of bots in a team        */ i(float, MUTATOR_ARGV_3_float) \
-    /**/                                   o(float, MUTATOR_ARGV_3_float) \
-    /** lowest scoring human in a team  */ i(entity, MUTATOR_ARGV_4_entity) \
-    /**/                                   o(entity, MUTATOR_ARGV_4_entity) \
-    /** lowest scoring bot in a team    */ i(entity, MUTATOR_ARGV_5_entity) \
-    /**/                                   o(entity, MUTATOR_ARGV_5_entity) \
-    /**/
-MUTATOR_HOOKABLE(GetTeamCount, EV_GetTeamCount);
-
-/** allows overriding best teams */
-#define EV_FindBestTeams(i, o) \
+    /** number of players in a team     */ o(float, MUTATOR_ARGV_2_float) \
+    /** number of bots in a team        */ o(float, MUTATOR_ARGV_3_float) \
+    /**/
+MUTATOR_HOOKABLE(TeamBalance_GetTeamCount, EV_TeamBalance_GetTeamCount);
+
+/** allows overriding the teams that will make the game most balanced if the
+ *  player joins any of them.
+ */
+#define EV_TeamBalance_FindBestTeams(i, o) \
     /** player checked   */ i(entity, MUTATOR_ARGV_0_entity) \
     /** bitmask of teams */ o(float, MUTATOR_ARGV_1_float) \
     /**/
-MUTATOR_HOOKABLE(FindBestTeams, EV_FindBestTeams);
+MUTATOR_HOOKABLE(TeamBalance_FindBestTeams, EV_TeamBalance_FindBestTeams);
+
+/** Called during autobalance. Return true to override the player that will be
+switched. */
+#define EV_TeamBalance_GetPlayerForTeamSwitch(i, o) \
+    /** source team index      */ i(int, MUTATOR_ARGV_0_int) \
+    /** destination team index */ i(int, MUTATOR_ARGV_1_int) \
+    /** is looking for bot     */ i(bool, MUTATOR_ARGV_2_bool) \
+    /** player to switch       */ o(entity, MUTATOR_ARGV_3_entity) \
+    /**/
+MUTATOR_HOOKABLE(TeamBalance_GetPlayerForTeamSwitch,
+       EV_TeamBalance_GetPlayerForTeamSwitch);
 
 /** copies variables for spectating "spectatee" to "this" */
 #define EV_SpectateCopy(i, o) \
@@ -1041,9 +1052,9 @@ MUTATOR_HOOKABLE(MonsterModel, EV_MonsterModel);
  * Called before player changes their team. Return true to block team change.
  */
 #define EV_Player_ChangeTeam(i, o) \
-    /** player */         i(entity, MUTATOR_ARGV_0_entity) \
-       /** current team */   i(float, MUTATOR_ARGV_1_float) \
-       /** new team */       i(float, MUTATOR_ARGV_2_float) \
+    /** player */             i(entity, MUTATOR_ARGV_0_entity) \
+    /** current team index */ i(float, MUTATOR_ARGV_1_float) \
+    /** new team index */     i(float, MUTATOR_ARGV_2_float) \
     /**/
 MUTATOR_HOOKABLE(Player_ChangeTeam, EV_Player_ChangeTeam);
 
@@ -1051,9 +1062,9 @@ MUTATOR_HOOKABLE(Player_ChangeTeam, EV_Player_ChangeTeam);
  * Called after player has changed their team.
  */
 #define EV_Player_ChangedTeam(i, o) \
-    /** player */         i(entity, MUTATOR_ARGV_0_entity) \
-       /** old team */       i(float, MUTATOR_ARGV_1_float) \
-       /** current team */   i(float, MUTATOR_ARGV_2_float) \
+    /** player */             i(entity, MUTATOR_ARGV_0_entity) \
+    /** old team index */     i(float, MUTATOR_ARGV_1_float) \
+    /** current team index */ i(float, MUTATOR_ARGV_2_float) \
     /**/
 MUTATOR_HOOKABLE(Player_ChangedTeam, EV_Player_ChangedTeam);
 
@@ -1174,3 +1185,21 @@ enum {
     MUT_VOTEPARSE_INVALID, // return -1 (vote parsed but counted as invalid, no action or vote)
     MUT_VOTEPARSE_UNACCEPTABLE // return 0 (vote parameter counted as unacceptable, warns caller)
 };
+
+/**
+ * Called when freezing an entity (monster or player), return true to force showing a waypoint
+ */
+#define EV_Freeze(i, o) \
+    /** targ */             i(entity, MUTATOR_ARGV_0_entity) \
+    /** revive speed */     i(float, MUTATOR_ARGV_1_float) \
+    /** frozen type */      i(int, MUTATOR_ARGV_2_int) \
+    /**/
+MUTATOR_HOOKABLE(Freeze, EV_Freeze);
+
+/**
+ * Called when an entity (monster or player) is defrosted
+ */
+#define EV_Unfreeze(i, o) \
+    /** targ */             i(entity, MUTATOR_ARGV_0_entity) \
+    /**/
+MUTATOR_HOOKABLE(Unfreeze, EV_Unfreeze);
index cc58cdc6d7ca7e2bc493b9c2bd1518a3aaa3bbe2..3755da96386ed98e6b10f9a754185a7f6b487951 100644 (file)
@@ -462,6 +462,16 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                                this.v_angle_y = this.v_angle.y + (random() * 2 - 1) * shake;
                                this.v_angle_x = bound(-90, this.v_angle.x, 90);
                        }
+
+                       if (this != attacker) {
+                               float realdmg = damage - excess;
+                               if (IS_PLAYER(attacker)) {
+                                       GameRules_scoring_add(attacker, DMG, realdmg);
+                               }
+                               if (IS_PLAYER(this)) {
+                                       GameRules_scoring_add(this, DMGTAKEN, realdmg);
+                               }
+                       }
                }
                else
                        this.max_armorvalue += (save + take);
@@ -470,16 +480,6 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
        this.dmg_take = this.dmg_take + take;//max(take - 10, 0);
        this.dmg_inflictor = inflictor;
 
-       if (this != attacker) {
-               float realdmg = damage - excess;
-               if (IS_PLAYER(attacker)) {
-                       GameRules_scoring_add(attacker, DMG, realdmg);
-               }
-               if (IS_PLAYER(this)) {
-                       GameRules_scoring_add(this, DMGTAKEN, realdmg);
-               }
-       }
-
        bool abot = (IS_BOT_CLIENT(attacker));
        bool vbot = (IS_BOT_CLIENT(this));
 
@@ -675,21 +675,6 @@ bool PlayerHeal(entity targ, entity inflictor, float amount, float limit)
        return true;
 }
 
-bool MoveToTeam(entity client, int team_colour, int type)
-{
-       int lockteams_backup = lockteams;  // backup any team lock
-       lockteams = 0;  // disable locked teams
-       TeamchangeFrags(client);  // move the players frags
-       if (!SetPlayerTeamSimple(client, team_colour))
-       {
-               return false;
-       }
-       Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE.m_id, DMG_NOWEP, client.origin, '0 0 0');  // kill the player
-       lockteams = lockteams_backup;  // restore the team lock
-       LogTeamchange(client.playerid, client.team, type);
-       return true;
-}
-
 /**
  * message "": do not say, just test flood control
  * return value:
index 8c9bac9b62aaa8e94ea4a594e33f6b680f67d74c..2853f7f6d4c3887b2f6c4f8fcaf24c4624ed4e92 100644 (file)
@@ -2,7 +2,7 @@
 
 .entity pusher;
 .float pushltime;
-.float istypefrag;
+.bool istypefrag;
 
 .float CopyBody_nextthink;
 .void(entity this) CopyBody_think;
@@ -30,13 +30,6 @@ void calculate_player_respawn_time(entity this);
 
 void ClientKill_Now_TeamChange(entity this);
 
-/// \brief Moves player to the specified team.
-/// \param[in,out] client Client to move.
-/// \param[in] team_colour Color of the team.
-/// \param[in] type ???
-/// \return True on success, false otherwise.
-bool MoveToTeam(entity client, float team_colour, float type);
-
 void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force);
 
 bool PlayerHeal(entity targ, entity inflictor, float amount, float limit);
index ae64e74e4909d66882ea09e261926086977b4da0..d347fcbaf9be95d010a8af0378795ffe3c9fe315 100644 (file)
@@ -86,7 +86,7 @@ void round_handler_FirstThink(entity this)
        this.nextthink = max(time, game_starttime);
 }
 
-void round_handler_Spawn(float() canRoundStart_func, float() canRoundEnd_func, void() roundStart_func)
+void round_handler_Spawn(bool() canRoundStart_func, bool() canRoundEnd_func, void() roundStart_func)
 {
        if (round_handler)
        {
index e6b17b0e775d76f1868c05d592c633844b1b8b8b..5979eb5c33f810faeb55f2add99f7574533fc121 100644 (file)
@@ -3,17 +3,17 @@
 entity round_handler;
 .float delay; // stores delay from round end to countdown start
 .float count; // stores initial number of the countdown
-.float wait; // it's set to true when round ends, to false when countdown starts
+.bool wait; // it's set to true when round ends, to false when countdown starts
 .float cnt;    // its initial value is .count + 1, then decreased while counting down
                        // reaches 0 when the round starts
 .float round_timelimit;
 .float round_endtime;
-.float() canRoundStart;
-.float() canRoundEnd;
+.bool() canRoundStart;
+.bool() canRoundEnd;
 .void() roundStart;
 
 void round_handler_Init(float the_delay, float the_count, float the_round_timelimit);
-void round_handler_Spawn(float() canRoundStart_func, float() canRoundEnd_func, void() roundStart_func);
+void round_handler_Spawn(bool() canRoundStart_func, bool() canRoundEnd_func, void() roundStart_func);
 void round_handler_Reset(float next_think);
 void round_handler_Remove();
 
index 160b5df5e4cfb21c279b96c39d28dbe6965b27d4..39dbd49a35ddc630c85c849624330e1785d30d01 100644 (file)
@@ -17,8 +17,6 @@ int NumTeams(int teams)
 int AvailableTeams()
 {
        return NumTeams(ScoreRules_teams);
-       // NOTE: this method is unreliable, as forced teams set the c* globals to weird values
-       //return boolean(c1 >= 0) + boolean(c2 >= 0) + boolean(c3 >= 0) + boolean(c4 >= 0);
 }
 
 // NOTE: ST_constants may not be >= MAX_TEAMSCORE
@@ -64,12 +62,11 @@ void ScoreRules_basics_end()
 void ScoreRules_generic()
 {
     int teams = 0;
-       if (teamplay) {
-               CheckAllowedTeams(NULL);
-               if (c1 >= 0) teams |= BIT(0);
-               if (c2 >= 0) teams |= BIT(1);
-               if (c3 >= 0) teams |= BIT(2);
-               if (c4 >= 0) teams |= BIT(3);
+       if (teamplay)
+       {
+               entity balance = TeamBalance_CheckAllowedTeams(NULL);
+               teams = TeamBalance_GetAllowedTeams(balance);
+               TeamBalance_Destroy(balance);
        }
        GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {});
 }
index b0d9e0992eb921c204451f24b48877010c082369..2c41ae18bdfc77b22113f5f36f40df8cb5d7ba23 100644 (file)
 #include <common/gamemodes/_mod.qh>
 #include "../common/teams.qh"
 
-void TeamchangeFrags(entity e)
+/// \brief Describes a state of team balance entity.
+enum
 {
-       PlayerScore_Clear(e);
-}
+       TEAM_BALANCE_UNINITIALIZED, ///< The team balance has not been initialized.
+       /// \brief TeamBalance_CheckAllowedTeams has been called.
+       TEAM_BALANCE_TEAMS_CHECKED,
+       /// \brief TeamBalance_GetTeamCounts has been called.
+       TEAM_BALANCE_TEAM_COUNTS_FILLED
+};
 
-void LogTeamchange(float player_id, float team_number, float type)
-{
-       if(!autocvar_sv_eventlog)
-               return;
+/// \brief Indicates that the player is not allowed to join a team.
+const int TEAM_NOT_ALLOWED = -1;
 
-       if(player_id < 1)
-               return;
+.int m_team_balance_state; ///< Holds the state of the team balance entity.
+.entity m_team_balance_team[NUM_TEAMS]; ///< ???
 
-       GameLogEcho(strcat(":team:", ftos(player_id), ":", ftos(team_number), ":", ftos(type)));
-}
+.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.
+.int m_num_players_alive; ///< Number of alive players in a team.
+.int m_num_control_points; ///< Number of control points owned by a team.
+
+entity g_team_entities[NUM_TEAMS]; ///< Holds global team entities.
 
-void default_delayedinit(entity this)
+STATIC_INIT(g_team_entities)
 {
-       if(!scores_initialized)
-               ScoreRules_generic();
+       for (int i = 0; i < NUM_TEAMS; ++i)
+       {
+               g_team_entities[i] = spawn();
+       }
 }
 
-void InitGameplayMode()
+entity Team_GetTeamFromIndex(int index)
 {
-       VoteReset();
-
-       // find out good world mins/maxs bounds, either the static bounds found by looking for solid, or the mapinfo specified bounds
-       get_mi_min_max(1);
-       // assign reflectively to avoid "assignment to world" warning
-       int done = 0; for (int i = 0, n = numentityfields(); i < n; ++i) {
-           string k = entityfieldname(i); vector v = (k == "mins") ? mi_min : (k == "maxs") ? mi_max : '0 0 0';
-           if (v) {
-            putentityfieldstring(i, world, sprintf("%v", v));
-            if (++done == 2) break;
-        }
-       }
-       // currently, NetRadiant's limit is 131072 qu for each side
-       // distance from one corner of a 131072qu cube to the opposite corner is approx. 227023 qu
-       // set the distance according to map size but don't go over the limit to avoid issues with float precision
-       // in case somebody makes extremely large maps
-       max_shot_distance = min(230000, vlen(world.maxs - world.mins));
-
-       MapInfo_LoadMapSettings(mapname);
-       GameRules_teams(false);
-
-       if (!cvar_value_issafe(world.fog))
-       {
-               LOG_INFO("The current map contains a potentially harmful fog setting, ignored");
-               world.fog = string_null;
-       }
-       if(MapInfo_Map_fog != "")
-               if(MapInfo_Map_fog == "none")
-                       world.fog = string_null;
-               else
-                       world.fog = strzone(MapInfo_Map_fog);
-       clientstuff = strzone(MapInfo_Map_clientstuff);
-
-       MapInfo_ClearTemps();
-
-       gamemode_name = MapInfo_Type_ToText(MapInfo_LoadedGametype);
-
-       cache_mutatormsg = strzone("");
-       cache_lastmutatormsg = strzone("");
-
-       InitializeEntity(NULL, default_delayedinit, INITPRIO_GAMETYPE_FALLBACK);
+       if (!Team_IsValidIndex(index))
+       {
+               LOG_FATALF("Team_GetTeamFromIndex: Index is invalid: %f", index);
+       }
+       return g_team_entities[index - 1];
 }
 
-string GetClientVersionMessage(entity this)
+entity Team_GetTeam(int team_num)
 {
-       if (CS(this).version_mismatch) {
-               if(CS(this).version < autocvar_gameversion) {
-                       return strcat("This is Xonotic ", autocvar_g_xonoticversion,
-                               "\n^3Your client version is outdated.\n\n\n### YOU WON'T BE ABLE TO PLAY ON THIS SERVER ###\n\n\nPlease update!!!^8");
-               } else {
-                       return strcat("This is Xonotic ", autocvar_g_xonoticversion,
-                               "\n^3This server is using an outdated Xonotic version.\n\n\n ### THIS SERVER IS INCOMPATIBLE AND THUS YOU CANNOT JOIN ###.^8");
-               }
-       } else {
-               return strcat("Welcome to Xonotic ", autocvar_g_xonoticversion);
+       if (!Team_IsValidTeam(team_num))
+       {
+               LOG_FATALF("Team_GetTeam: Value is invalid: %f", team_num);
        }
+       return g_team_entities[Team_TeamToIndex(team_num) - 1];
 }
 
-string getwelcomemessage(entity this)
+float Team_GetTeamScore(entity team_ent)
 {
-       MUTATOR_CALLHOOK(BuildMutatorsPrettyString, "");
-       string modifications = M_ARGV(0, string);
+       return team_ent.m_team_score;
+}
 
-       if(g_weaponarena)
-       {
-               if(g_weaponarena_random)
-                       modifications = strcat(modifications, ", ", ftos(g_weaponarena_random), " of ", g_weaponarena_list, " Arena"); // TODO: somehow get this into the mutator
-               else
-                       modifications = strcat(modifications, ", ", g_weaponarena_list, " Arena");
-       }
-       else if(cvar("g_balance_blaster_weaponstartoverride") == 0)
-               modifications = strcat(modifications, ", No start weapons");
-       if(cvar("sv_gravity") < stof(cvar_defstring("sv_gravity")))
-               modifications = strcat(modifications, ", Low gravity");
-       if(g_weapon_stay && !g_cts)
-               modifications = strcat(modifications, ", Weapons stay");
-       if(g_jetpack)
-               modifications = strcat(modifications, ", Jetpack");
-       if(autocvar_g_powerups == 0)
-               modifications = strcat(modifications, ", No powerups");
-       if(autocvar_g_powerups > 0)
-               modifications = strcat(modifications, ", Powerups");
-       modifications = substring(modifications, 2, strlen(modifications) - 2);
+void Team_SetTeamScore(entity team_ent, float score)
+{
+       team_ent.m_team_score = score;
+}
 
-       string versionmessage = GetClientVersionMessage(this);
-       string s = strcat(versionmessage, "^8\n^8\nmatch type is ^1", gamemode_name, "^8\n");
+int Team_GetNumberOfAlivePlayers(entity team_ent)
+{
+       return team_ent.m_num_players_alive;
+}
 
-       if(modifications != "")
-               s = strcat(s, "^8\nactive modifications: ^3", modifications, "^8\n");
+void Team_SetNumberOfAlivePlayers(entity team_ent, int number)
+{
+       team_ent.m_num_players_alive = number;
+}
 
-       if(cache_lastmutatormsg != autocvar_g_mutatormsg)
+int Team_GetNumberOfAliveTeams()
+{
+       int result = 0;
+       for (int i = 0; i < NUM_TEAMS; ++i)
        {
-               strcpy(cache_lastmutatormsg, autocvar_g_mutatormsg);
-               strcpy(cache_mutatormsg, cache_lastmutatormsg);
-       }
-
-       if (cache_mutatormsg != "") {
-               s = strcat(s, "\n\n^8special gameplay tips: ^7", cache_mutatormsg);
+               if (g_team_entities[i].m_num_players_alive > 0)
+               {
+                       ++result;
+               }
        }
+       return result;
+}
 
-       string mutator_msg = "";
-       MUTATOR_CALLHOOK(BuildGameplayTipsString, mutator_msg);
-       mutator_msg = M_ARGV(0, string);
+int Team_GetNumberOfControlPoints(entity team_ent)
+{
+       return team_ent.m_num_control_points;
+}
 
-       s = strcat(s, mutator_msg); // trust that the mutator will do proper formatting
+void Team_SetNumberOfControlPoints(entity team_ent, int number)
+{
+       team_ent.m_num_control_points = number;
+}
 
-       string motd = autocvar_sv_motd;
-       if (motd != "") {
-               s = strcat(s, "\n\n^8MOTD: ^7", strreplace("\\n", "\n", motd));
+int Team_GetNumberOfTeamsWithControlPoints()
+{
+       int result = 0;
+       for (int i = 0; i < NUM_TEAMS; ++i)
+       {
+               if (g_team_entities[i].m_num_control_points > 0)
+               {
+                       ++result;
+               }
        }
-       return s;
+       return result;
 }
 
 void setcolor(entity this, int clr)
@@ -162,6 +131,26 @@ void setcolor(entity this, int clr)
 #endif
 }
 
+bool Entity_HasValidTeam(entity this)
+{
+       return Team_IsValidTeam(this.team);
+}
+
+int Entity_GetTeamIndex(entity this)
+{
+       return Team_TeamToIndex(this.team);
+}
+
+entity Entity_GetTeam(entity this)
+{
+       int index = Entity_GetTeamIndex(this);
+       if (!Team_IsValidIndex(index))
+       {
+               return NULL;
+       }
+       return Team_GetTeamFromIndex(index);
+}
+
 void SetPlayerColors(entity player, float _color)
 {
        float pants = _color & 0x0F;
@@ -176,748 +165,712 @@ void SetPlayerColors(entity player, float _color)
        }
 }
 
-void KillPlayerForTeamChange(entity player)
+bool Player_SetTeamIndex(entity player, int index)
 {
-       if (IS_DEAD(player))
+       int new_team = Team_IndexToTeam(index);
+       if (player.team == new_team)
        {
-               return;
+               if (new_team != -1)
+               {
+                       // This is important when players join the game and one of their
+                       // color matches the team color while other doesn't. For example
+                       // [BOT]Lion.
+                       SetPlayerColors(player, new_team - 1);
+               }
+               return true;
        }
-       if (MUTATOR_CALLHOOK(Player_ChangeTeamKill, player) == true)
+       int old_index = Team_TeamToIndex(player.team);
+       if (MUTATOR_CALLHOOK(Player_ChangeTeam, player, old_index, index) == true)
        {
-               return;
+               // Mutator has blocked team change.
+               return false;
        }
-       Damage(player, player, player, 100000, DEATH_TEAMCHANGE.m_id, DMG_NOWEP, player.origin,
-               '0 0 0');
+       if (new_team == -1)
+       {
+               player.team = -1;
+       }
+       else
+       {
+               SetPlayerColors(player, new_team - 1);
+       }
+       MUTATOR_CALLHOOK(Player_ChangedTeam, player, old_index, index);
+       return true;
 }
 
-bool SetPlayerTeamSimple(entity player, int team_num)
+bool SetPlayerTeam(entity player, int team_index, int type)
 {
-       if (player.team == team_num)
+       int old_team_index = Entity_GetTeamIndex(player);
+       if (!Player_SetTeamIndex(player, team_index))
        {
-               // This is important when players join the game and one of their color
-               // matches the team color while other doesn't. For example [BOT]Lion.
-               SetPlayerColors(player, team_num - 1);
-               return true;
+               return false;
        }
-       if (MUTATOR_CALLHOOK(Player_ChangeTeam, player, Team_TeamToNumber(
-               player.team), Team_TeamToNumber(team_num)) == true)
+       LogTeamchange(player.playerid, player.team, type);
+       if (team_index != old_team_index)
        {
-               // Mutator has blocked team change.
-               return false;
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(player.team,
+                       INFO_JOIN_PLAY_TEAM), player.netname);
+               KillPlayerForTeamChange(player);
        }
-       int old_team = player.team;
-       SetPlayerColors(player, team_num - 1);
-       MUTATOR_CALLHOOK(Player_ChangedTeam, player, old_team, player.team);
        return true;
 }
 
-bool SetPlayerTeam(entity player, int destination_team, int source_team,
-       bool no_print)
+bool MoveToTeam(entity client, int team_index, int type)
 {
-       int team_num = Team_NumberToTeam(destination_team);
-       if (!SetPlayerTeamSimple(player, team_num))
+       //PrintToChatAll(sprintf("MoveToTeam: %s, %f", client.netname, team_index));
+       int lockteams_backup = lockteams;  // backup any team lock
+       lockteams = 0;  // disable locked teams
+       PlayerScore_Clear(client);
+       if (!SetPlayerTeam(client, team_index, type))
        {
+               lockteams = lockteams_backup;  // restore the team lock
                return false;
        }
-       LogTeamchange(player.playerid, player.team, 3);  // log manual team join
-       if (no_print)
+       lockteams = lockteams_backup;  // restore the team lock
+       return true;
+}
+
+void KillPlayerForTeamChange(entity player)
+{
+       if (IS_DEAD(player))
+       {
+               return;
+       }
+       if (MUTATOR_CALLHOOK(Player_ChangeTeamKill, player) == true)
        {
-               return true;
+               return;
        }
-       bprint(playername(player, false), "^7 has changed from ", Team_NumberToColoredFullName(source_team), "^7 to ", Team_NumberToColoredFullName(destination_team), "\n");
-       return true;
+       Damage(player, player, player, 100000, DEATH_TEAMCHANGE.m_id, DMG_NOWEP,
+               player.origin, '0 0 0');
 }
 
-// set c1...c4 to show what teams are allowed
-void CheckAllowedTeams(entity for_whom)
+void LogTeamchange(float player_id, float team_number, int type)
 {
-       int teams_mask = 0;
+       if(!autocvar_sv_eventlog)
+               return;
+
+       if(player_id < 1)
+               return;
 
-       c1 = c2 = c3 = c4 = -1;
-       num_bots_team1 = num_bots_team2 = num_bots_team3 = num_bots_team4 = 0;
+       GameLogEcho(strcat(":team:", ftos(player_id), ":", ftos(team_number), ":", ftos(type)));
+}
 
+entity TeamBalance_CheckAllowedTeams(entity for_whom)
+{
+       entity balance = spawn();
+       for (int i = 0; i < NUM_TEAMS; ++i)
+       {
+               entity team_ent = balance.m_team_balance_team[i] = spawn();
+               team_ent.m_team_score = g_team_entities[i].m_team_score;
+               team_ent.m_num_players = TEAM_NOT_ALLOWED;
+               team_ent.m_num_bots = 0;
+       }
+       setthink(balance, TeamBalance_Destroy);
+       
+       int teams_mask = 0;     
        string teament_name = string_null;
-
-       bool mutator_returnvalue = MUTATOR_CALLHOOK(CheckAllowedTeams, teams_mask, teament_name, for_whom);
+       bool mutator_returnvalue = MUTATOR_CALLHOOK(TeamBalance_CheckAllowedTeams,
+               teams_mask, teament_name, for_whom);
        teams_mask = M_ARGV(0, float);
        teament_name = M_ARGV(1, string);
-
-       if(!mutator_returnvalue)
+       if (mutator_returnvalue)
        {
-               if(teams_mask & BIT(0)) c1 = 0;
-               if(teams_mask & BIT(1)) c2 = 0;
-               if(teams_mask & BIT(2)) c3 = 0;
-               if(teams_mask & BIT(3)) c4 = 0;
+               for (int i = 0; i < NUM_TEAMS; ++i)
+               {
+                       if (teams_mask & BIT(i))
+                       {
+                               balance.m_team_balance_team[i].m_num_players = 0;
+                       }
+               }
        }
 
-       // find out what teams are allowed if necessary
-       if(teament_name)
+       if (teament_name)
        {
                entity head = find(NULL, classname, teament_name);
-               while(head)
+               while (head)
                {
-                       switch(head.team)
+                       if (Team_IsValidTeam(head.team))
                        {
-                               case NUM_TEAM_1: c1 = 0; break;
-                               case NUM_TEAM_2: c2 = 0; break;
-                               case NUM_TEAM_3: c3 = 0; break;
-                               case NUM_TEAM_4: c4 = 0; break;
+                               TeamBalance_GetTeam(balance, head.team).m_num_players = 0;
                        }
-
                        head = find(head, classname, teament_name);
                }
        }
 
        // TODO: Balance quantity of bots across > 2 teams when bot_vs_human is set (and remove next line)
-       if(AvailableTeams() == 2)
-       if(autocvar_bot_vs_human && for_whom)
+       if (AvailableTeams() == 2)
+       if (autocvar_bot_vs_human && for_whom)
        {
-               if(autocvar_bot_vs_human > 0)
+               if (autocvar_bot_vs_human > 0)
                {
                        // find last team available
-
-                       if(IS_BOT_CLIENT(for_whom))
+                       if (IS_BOT_CLIENT(for_whom))
                        {
-                               if(c4 >= 0) { c3 = c2 = c1 = -1; }
-                               else if(c3 >= 0) { c4 = c2 = c1 = -1; }
-                               else { c4 = c3 = c1 = -1; }
+                               if (TeamBalance_IsTeamAllowedInternal(balance, 4))
+                               {
+                                       TeamBalance_BanTeamsExcept(balance, 4);
+                               }
+                               else if (TeamBalance_IsTeamAllowedInternal(balance, 3))
+                               {
+                                       TeamBalance_BanTeamsExcept(balance, 3);
+                               }
+                               else
+                               {
+                                       TeamBalance_BanTeamsExcept(balance, 2);
+                               }
                                // no further cases, we know at least 2 teams exist
                        }
                        else
                        {
-                               if(c1 >= 0) { c2 = c3 = c4 = -1; }
-                               else if(c2 >= 0) { c1 = c3 = c4 = -1; }
-                               else { c1 = c2 = c4 = -1; }
+                               if (TeamBalance_IsTeamAllowedInternal(balance, 1))
+                               {
+                                       TeamBalance_BanTeamsExcept(balance, 1);
+                               }
+                               else if (TeamBalance_IsTeamAllowedInternal(balance, 2))
+                               {
+                                       TeamBalance_BanTeamsExcept(balance, 2);
+                               }
+                               else
+                               {
+                                       TeamBalance_BanTeamsExcept(balance, 3);
+                               }
                                // no further cases, bots have one of the teams
                        }
                }
                else
                {
                        // find first team available
-
-                       if(IS_BOT_CLIENT(for_whom))
+                       if (IS_BOT_CLIENT(for_whom))
                        {
-                               if(c1 >= 0) { c2 = c3 = c4 = -1; }
-                               else if(c2 >= 0) { c1 = c3 = c4 = -1; }
-                               else { c1 = c2 = c4 = -1; }
+                               if (TeamBalance_IsTeamAllowedInternal(balance, 1))
+                               {
+                                       TeamBalance_BanTeamsExcept(balance, 1);
+                               }
+                               else if (TeamBalance_IsTeamAllowedInternal(balance, 2))
+                               {
+                                       TeamBalance_BanTeamsExcept(balance, 2);
+                               }
+                               else
+                               {
+                                       TeamBalance_BanTeamsExcept(balance, 3);
+                               }
                                // no further cases, we know at least 2 teams exist
                        }
                        else
                        {
-                               if(c4 >= 0) { c3 = c2 = c1 = -1; }
-                               else if(c3 >= 0) { c4 = c2 = c1 = -1; }
-                               else { c4 = c3 = c1 = -1; }
+                               if (TeamBalance_IsTeamAllowedInternal(balance, 4))
+                               {
+                                       TeamBalance_BanTeamsExcept(balance, 4);
+                               }
+                               else if (TeamBalance_IsTeamAllowedInternal(balance, 3))
+                               {
+                                       TeamBalance_BanTeamsExcept(balance, 3);
+                               }
+                               else
+                               {
+                                       TeamBalance_BanTeamsExcept(balance, 2);
+                               }
                                // no further cases, bots have one of the teams
                        }
                }
        }
 
-       if(!for_whom)
-               return;
+       if (!for_whom)
+       {
+               balance.m_team_balance_state = TEAM_BALANCE_TEAMS_CHECKED;
+               return balance;
+       }
 
        // if player has a forced team, ONLY allow that one
-       if(for_whom.team_forced == NUM_TEAM_1 && c1 >= 0)
-               c2 = c3 = c4 = -1;
-       else if(for_whom.team_forced == NUM_TEAM_2 && c2 >= 0)
-               c1 = c3 = c4 = -1;
-       else if(for_whom.team_forced == NUM_TEAM_3 && c3 >= 0)
-               c1 = c2 = c4 = -1;
-       else if(for_whom.team_forced == NUM_TEAM_4 && c4 >= 0)
-               c1 = c2 = c3 = -1;
+       for (int i = 1; i <= NUM_TEAMS; ++i)
+       {
+               if (for_whom.team_forced == Team_IndexToTeam(i) &&
+                       TeamBalance_IsTeamAllowedInternal(balance, i))
+               {
+                       TeamBalance_BanTeamsExcept(balance, i);
+               }
+               break;
+       }
+       balance.m_team_balance_state = TEAM_BALANCE_TEAMS_CHECKED;
+       return balance;
 }
 
-float PlayerValue(entity p)
+void TeamBalance_Destroy(entity balance)
 {
-       return 1;
-       // FIXME: it always returns 1...
+       if (balance == NULL)
+       {
+               return;
+       }
+       for (int i = 0; i < NUM_TEAMS; ++i)
+       {
+               delete(balance.(m_team_balance_team[i]));
+       }
+       delete(balance);
 }
 
-// c1...c4 should be set to -1 (not allowed) or 0 (allowed).
-// teams that are allowed will now have their player counts stored in c1...c4
-void GetTeamCounts(entity ignore)
+int TeamBalance_GetAllowedTeams(entity balance)
 {
-       if (MUTATOR_CALLHOOK(GetTeamCounts) == true)
+       if (balance == NULL)
        {
-               if (c1 >= 0)
-               {
-                       MUTATOR_CALLHOOK(GetTeamCount, NUM_TEAM_1, ignore, c1,
-                               num_bots_team1, lowest_human_team1, lowest_bot_team1);
-                       c1 = M_ARGV(2, float);
-                       num_bots_team1 = M_ARGV(3, float);
-                       lowest_human_team1 = M_ARGV(4, entity);
-                       lowest_bot_team1 = M_ARGV(5, entity);
-               }
-               if (c2 >= 0)
-               {
-                       MUTATOR_CALLHOOK(GetTeamCount, NUM_TEAM_2, ignore, c2,
-                               num_bots_team2, lowest_human_team2, lowest_bot_team2);
-                       c2 = M_ARGV(2, float);
-                       num_bots_team2 = M_ARGV(3, float);
-                       lowest_human_team2 = M_ARGV(4, entity);
-                       lowest_bot_team2 = M_ARGV(5, entity);
-               }
-               if (c3 >= 0)
+               LOG_FATAL("TeamBalance_GetAllowedTeams: Team balance entity is NULL.");
+       }
+       if (balance.m_team_balance_state == TEAM_BALANCE_UNINITIALIZED)
+       {
+               LOG_FATAL("TeamBalance_GetAllowedTeams: "
+                       "Team balance entity is not initialized.");
+       }
+       int result = 0;
+       for (int i = 1; i <= NUM_TEAMS; ++i)
+       {
+               if (TeamBalance_IsTeamAllowedInternal(balance, i))
                {
-                       MUTATOR_CALLHOOK(GetTeamCount, NUM_TEAM_3, ignore, c3,
-                               num_bots_team3, lowest_human_team3, lowest_bot_team3);
-                       c3 = M_ARGV(2, float);
-                       num_bots_team3 = M_ARGV(3, float);
-                       lowest_human_team3 = M_ARGV(4, entity);
-                       lowest_bot_team3 = M_ARGV(5, entity);
+                       result |= Team_IndexToBit(i);
                }
-               if (c4 >= 0)
+       }
+       return result;
+}
+
+bool TeamBalance_IsTeamAllowed(entity balance, int index)
+{
+       if (balance == NULL)
+       {
+               LOG_FATAL("TeamBalance_IsTeamAllowed: Team balance entity is NULL.");
+       }
+       if (balance.m_team_balance_state == TEAM_BALANCE_UNINITIALIZED)
+       {
+               LOG_FATAL("TeamBalance_IsTeamAllowed: "
+                       "Team balance entity is not initialized.");
+       }
+       if (!Team_IsValidIndex(index))
+       {
+               LOG_FATALF("TeamBalance_IsTeamAllowed: Team index is invalid: %f",
+                       index);
+       }
+       return TeamBalance_IsTeamAllowedInternal(balance, index);
+}
+
+void TeamBalance_GetTeamCounts(entity balance, entity ignore)
+{
+       if (balance == NULL)
+       {
+               LOG_FATAL("TeamBalance_GetTeamCounts: Team balance entity is NULL.");
+       }
+       if (balance.m_team_balance_state == TEAM_BALANCE_UNINITIALIZED)
+       {
+               LOG_FATAL("TeamBalance_GetTeamCounts: "
+                       "Team balance entity is not initialized.");
+       }
+       if (MUTATOR_CALLHOOK(TeamBalance_GetTeamCounts) == true)
+       {
+               // Mutator has overriden the configuration.
+               for (int i = 1; i <= NUM_TEAMS; ++i)
                {
-                       MUTATOR_CALLHOOK(GetTeamCount, NUM_TEAM_4, ignore,
-                               c4, num_bots_team4, lowest_human_team4, lowest_bot_team4);
-                       c4 = M_ARGV(2, float);
-                       num_bots_team4 = M_ARGV(3, float);
-                       lowest_human_team4 = M_ARGV(4, entity);
-                       lowest_bot_team4 = M_ARGV(5, entity);
+                       entity team_ent = TeamBalance_GetTeamFromIndex(balance, i);
+                       if (TeamBalanceTeam_IsAllowed(team_ent))
+                       {
+                               MUTATOR_CALLHOOK(TeamBalance_GetTeamCount, i, ignore);
+                               team_ent.m_num_players = M_ARGV(2, float);
+                               team_ent.m_num_bots = M_ARGV(3, float);
+                       }
                }
        }
        else
        {
-               float value, bvalue;
-               // now count how many players are on each team already
-               float lowest_human_score1 = FLOAT_MAX;
-               float lowest_bot_score1 = FLOAT_MAX;
-               float lowest_human_score2 = FLOAT_MAX;
-               float lowest_bot_score2 = FLOAT_MAX;
-               float lowest_human_score3 = FLOAT_MAX;
-               float lowest_bot_score3 = FLOAT_MAX;
-               float lowest_human_score4 = FLOAT_MAX;
-               float lowest_bot_score4 = FLOAT_MAX;
+               // Manually count all players.
                FOREACH_CLIENT(true,
                {
-                       float t;
+                       if (it == ignore)
+                       {
+                               continue;
+                       }
+                       int team_num;
                        if (IS_PLAYER(it) || it.caplayer)
                        {
-                               t = it.team;
+                               team_num = it.team;
                        }
                        else if (it.team_forced > 0)
                        {
-                               t = it.team_forced; // reserve the spot
+                               team_num = it.team_forced; // reserve the spot
                        }
                        else
                        {
                                continue;
                        }
-                       if (it == ignore)
+                       if (!Team_IsValidTeam(team_num))
                        {
                                continue;
                        }
-                       value = PlayerValue(it);
-                       if (IS_BOT_CLIENT(it))
-                       {
-                               bvalue = value;
-                       }
-                       else
-                       {
-                               bvalue = 0;
-                       }
-                       if (value == 0)
+                       entity team_ent = TeamBalance_GetTeam(balance, team_num);
+                       if (!TeamBalanceTeam_IsAllowed(team_ent))
                        {
                                continue;
                        }
-                       switch (t)
+                       ++team_ent.m_num_players;
+                       if (IS_BOT_CLIENT(it))
                        {
-                               case NUM_TEAM_1:
-                               {
-                                       if (c1 < 0)
-                                       {
-                                               break;
-                                       }
-                                       c1 += value;
-                                       num_bots_team1 += bvalue;
-                                       float temp_score = PlayerScore_Get(it, SP_SCORE);
-                                       if (!bvalue)
-                                       {
-                                               if (temp_score < lowest_human_score1)
-                                               {
-                                                       lowest_human_team1 = it;
-                                                       lowest_human_score1 = temp_score;
-                                               }
-                                               break;
-                                       }
-                                       if (temp_score < lowest_bot_score1)
-                                       {
-                                               lowest_bot_team1 = it;
-                                               lowest_bot_score1 = temp_score;
-                                       }
-                                       break;
-                               }
-                               case NUM_TEAM_2:
-                               {
-                                       if (c2 < 0)
-                                       {
-                                               break;
-                                       }
-                                       c2 += value;
-                                       num_bots_team2 += bvalue;
-                                       float temp_score = PlayerScore_Get(it, SP_SCORE);
-                                       if (!bvalue)
-                                       {
-                                               if (temp_score < lowest_human_score2)
-                                               {
-                                                       lowest_human_team2 = it;
-                                                       lowest_human_score2 = temp_score;
-                                               }
-                                               break;
-                                       }
-                                       if (temp_score < lowest_bot_score2)
-                                       {
-                                               lowest_bot_team2 = it;
-                                               lowest_bot_score2 = temp_score;
-                                       }
-                                       break;
-                               }
-                               case NUM_TEAM_3:
-                               {
-                                       if (c3 < 0)
-                                       {
-                                               break;
-                                       }
-                                       c3 += value;
-                                       num_bots_team3 += bvalue;
-                                       float temp_score = PlayerScore_Get(it, SP_SCORE);
-                                       if (!bvalue)
-                                       {
-                                               if (temp_score < lowest_human_score3)
-                                               {
-                                                       lowest_human_team3 = it;
-                                                       lowest_human_score3 = temp_score;
-                                               }
-                                               break;
-                                       }
-                                       if (temp_score < lowest_bot_score3)
-                                       {
-                                               lowest_bot_team3 = it;
-                                               lowest_bot_score3 = temp_score;
-                                       }
-                                       break;
-                               }
-                               case NUM_TEAM_4:
-                               {
-                                       if (c4 < 0)
-                                       {
-                                               break;
-                                       }
-                                       c4 += value;
-                                       num_bots_team4 += bvalue;
-                                       float temp_score = PlayerScore_Get(it, SP_SCORE);
-                                       if (!bvalue)
-                                       {
-                                               if (temp_score < lowest_human_score4)
-                                               {
-                                                       lowest_human_team4 = it;
-                                                       lowest_human_score4 = temp_score;
-                                               }
-                                               break;
-                                       }
-                                       if (temp_score < lowest_bot_score4)
-                                       {
-                                               lowest_bot_team4 = it;
-                                               lowest_bot_score4 = temp_score;
-                                       }
-                                       break;
-                               }
+                               ++team_ent.m_num_bots;
                        }
                });
        }
 
        // if the player who has a forced team has not joined yet, reserve the spot
-       if(autocvar_g_campaign)
+       if (autocvar_g_campaign)
        {
-               switch(autocvar_g_campaign_forceteam)
+               if (Team_IsValidIndex(autocvar_g_campaign_forceteam))
                {
-                       case 1: if(c1 == num_bots_team1) ++c1; break;
-                       case 2: if(c2 == num_bots_team2) ++c2; break;
-                       case 3: if(c3 == num_bots_team3) ++c3; break;
-                       case 4: if(c4 == num_bots_team4) ++c4; break;
+                       entity team_ent = TeamBalance_GetTeamFromIndex(balance,
+                               autocvar_g_campaign_forceteam);
+                       if (team_ent.m_num_players == team_ent.m_num_bots)
+                       {
+                               ++team_ent.m_num_players;
+                       }
                }
        }
+       balance.m_team_balance_state = TEAM_BALANCE_TEAM_COUNTS_FILLED;
 }
 
-bool IsTeamSmallerThanTeam(int team_a, int team_b, entity player,
-       bool use_score)
+int TeamBalance_GetNumberOfPlayers(entity balance, int index)
 {
-       if (!Team_IsValidNumber(team_a))
+       if (balance == NULL)
        {
-               LOG_FATALF("IsTeamSmallerThanTeam: team_a is invalid: %f", team_a);
+               LOG_FATAL("TeamBalance_GetNumberOfPlayers: "
+                       "Team balance entity is NULL.");
        }
-       if (!Team_IsValidNumber(team_b))
+       if (balance.m_team_balance_state != TEAM_BALANCE_TEAM_COUNTS_FILLED)
        {
-               LOG_FATALF("IsTeamSmallerThanTeam: team_b is invalid: %f", team_b);
+               LOG_FATAL("TeamBalance_GetNumberOfPlayers: "
+                       "TeamBalance_GetTeamCounts has not been called.");
        }
-       if (team_a == team_b)
+       if (!Team_IsValidIndex(index))
        {
-               return false;
+               LOG_FATALF("TeamBalance_GetNumberOfPlayers: Team index is invalid: %f",
+                       index);
        }
-       // we assume that CheckAllowedTeams and GetTeamCounts have already been called
-       int num_players_team_a = -1, num_players_team_b = -1;
-       int num_bots_team_a = 0, num_bots_team_b = 0;
-       float score_team_a = 0, score_team_b = 0;
-       switch (team_a)
-       {
-               case 1:
-               {
-                       num_players_team_a = c1;
-                       num_bots_team_a = num_bots_team1;
-                       score_team_a = team1_score;
-                       break;
-               }
-               case 2:
-               {
-                       num_players_team_a = c2;
-                       num_bots_team_a = num_bots_team2;
-                       score_team_a = team2_score;
-                       break;
-               }
-               case 3:
-               {
-                       num_players_team_a = c3;
-                       num_bots_team_a = num_bots_team3;
-                       score_team_a = team3_score;
-                       break;
-               }
-               case 4:
-               {
-                       num_players_team_a = c4;
-                       num_bots_team_a = num_bots_team4;
-                       score_team_a = team4_score;
-                       break;
-               }
-       }
-       switch (team_b)
+       return balance.m_team_balance_team[index - 1].m_num_players;
+}
+
+int TeamBalance_FindBestTeam(entity balance, entity player, bool ignore_player)
+{
+       if (balance == NULL)
        {
-               case 1:
-               {
-                       num_players_team_b = c1;
-                       num_bots_team_b = num_bots_team1;
-                       score_team_b = team1_score;
-                       break;
-               }
-               case 2:
-               {
-                       num_players_team_b = c2;
-                       num_bots_team_b = num_bots_team2;
-                       score_team_b = team2_score;
-                       break;
-               }
-               case 3:
-               {
-                       num_players_team_b = c3;
-                       num_bots_team_b = num_bots_team3;
-                       score_team_b = team3_score;
-                       break;
-               }
-               case 4:
-               {
-                       num_players_team_b = c4;
-                       num_bots_team_b = num_bots_team4;
-                       score_team_b = team4_score;
-                       break;
-               }
+               LOG_FATAL("TeamBalance_FindBestTeam: Team balance entity is NULL.");
        }
-       // invalid
-       if (num_players_team_a < 0 || num_players_team_b < 0)
+       if (balance.m_team_balance_state == TEAM_BALANCE_UNINITIALIZED)
        {
-               return false;
+               LOG_FATAL("TeamBalance_FindBestTeam: "
+                       "Team balance entity is not initialized.");
        }
-       if (IS_REAL_CLIENT(player) && bots_would_leave)
+       // count how many players are in each team
+       if (ignore_player)
        {
-               num_players_team_a -= num_bots_team_a;
-               num_players_team_b -= num_bots_team_b;
+               TeamBalance_GetTeamCounts(balance, player);
        }
-       if (!use_score)
+       else
        {
-               return num_players_team_a < num_players_team_b;
+               TeamBalance_GetTeamCounts(balance, NULL);
        }
-       if (num_players_team_a < num_players_team_b)
+       int team_bits = TeamBalance_FindBestTeams(balance, player, true);
+       if (team_bits == 0)
        {
-               return true;
+               LOG_FATALF("TeamBalance_FindBestTeam: No teams available for %s\n",
+                       MapInfo_Type_ToString(MapInfo_CurrentGametype()));
        }
-       if (num_players_team_a > num_players_team_b)
+       RandomSelection_Init();
+       for (int i = 1; i <= NUM_TEAMS; ++i)
        {
-               return false;
+               if (team_bits & Team_IndexToBit(i))
+               {
+                       RandomSelection_AddFloat(i, 1, 1);
+               }
        }
-       return score_team_a < score_team_b;
+       return RandomSelection_chosen_float;
 }
 
-bool IsTeamEqualToTeam(int team_a, int team_b, entity player, bool use_score)
+int TeamBalance_FindBestTeams(entity balance, entity player, bool use_score)
 {
-       if (!Team_IsValidNumber(team_a))
+       if (balance == NULL)
        {
-               LOG_FATALF("IsTeamEqualToTeam: team_a is invalid: %f", team_a);
+               LOG_FATAL("TeamBalance_FindBestTeams: Team balance entity is NULL.");
        }
-       if (!Team_IsValidNumber(team_b))
+       if (balance.m_team_balance_state != TEAM_BALANCE_TEAM_COUNTS_FILLED)
        {
-               LOG_FATALF("IsTeamEqualToTeam: team_b is invalid: %f", team_b);
+               LOG_FATAL("TeamBalance_FindBestTeams: "
+                       "TeamBalance_GetTeamCounts has not been called.");
        }
-       if (team_a == team_b)
+       if (MUTATOR_CALLHOOK(TeamBalance_FindBestTeams, player) == true)
        {
-               return true;
+               return M_ARGV(1, float);
        }
-       // we assume that CheckAllowedTeams and GetTeamCounts have already been called
-       int num_players_team_a = -1, num_players_team_b = -1;
-       int num_bots_team_a = 0, num_bots_team_b = 0;
-       float score_team_a = 0, score_team_b = 0;
-       switch (team_a)
+       int team_bits = 0;
+       int previous_team = 0;
+       for (int i = 1; i <= NUM_TEAMS; ++i)
        {
-               case 1:
+               if (!TeamBalance_IsTeamAllowedInternal(balance, i))
                {
-                       num_players_team_a = c1;
-                       num_bots_team_a = num_bots_team1;
-                       score_team_a = team1_score;
-                       break;
+                       continue;
                }
-               case 2:
+               if (previous_team == 0)
                {
-                       num_players_team_a = c2;
-                       num_bots_team_a = num_bots_team2;
-                       score_team_a = team2_score;
-                       break;
+                       team_bits = Team_IndexToBit(i);
+                       previous_team = i;
+                       continue;
                }
-               case 3:
+               int compare = TeamBalance_CompareTeams(balance, i, previous_team,
+                       player, use_score);
+               if (compare == TEAMS_COMPARE_LESS)
                {
-                       num_players_team_a = c3;
-                       num_bots_team_a = num_bots_team3;
-                       score_team_a = team3_score;
-                       break;
+                       team_bits = Team_IndexToBit(i);
+                       previous_team = i;
+                       continue;
                }
-               case 4:
+               if (compare == TEAMS_COMPARE_EQUAL)
                {
-                       num_players_team_a = c4;
-                       num_bots_team_a = num_bots_team4;
-                       score_team_a = team4_score;
-                       break;
+                       team_bits |= Team_IndexToBit(i);
+                       previous_team = i;
                }
        }
-       switch (team_b)
+       return team_bits;
+}
+
+void TeamBalance_JoinBestTeam(entity this)
+{
+       //PrintToChatAll(sprintf("JoinBestTeam: %s", this.netname));
+       if (!teamplay)
        {
-               case 1:
-               {
-                       num_players_team_b = c1;
-                       num_bots_team_b = num_bots_team1;
-                       score_team_b = team1_score;
-                       break;
-               }
-               case 2:
+               return;
+       }
+       if (this.bot_forced_team)
+       {
+               return;
+       }
+       int old_team_index = Team_TeamToIndex(this.team);
+       entity balance = TeamBalance_CheckAllowedTeams(this);
+       if (this.team_forced > 0)
+       {
+               int forced_team_index = Team_TeamToIndex(this.team_forced);
+               bool is_team_allowed = TeamBalance_IsTeamAllowedInternal(balance,
+                       forced_team_index);
+               TeamBalance_Destroy(balance);
+               if (!is_team_allowed)
                {
-                       num_players_team_b = c2;
-                       num_bots_team_b = num_bots_team2;
-                       score_team_b = team2_score;
-                       break;
+                       return;
                }
-               case 3:
+               if (!SetPlayerTeam(this, forced_team_index, TEAM_CHANGE_AUTO))
                {
-                       num_players_team_b = c3;
-                       num_bots_team_b = num_bots_team3;
-                       score_team_b = team3_score;
-                       break;
+                       return;
                }
-               case 4:
+               if ((old_team_index != -1) && !IS_BOT_CLIENT(this))
                {
-                       num_players_team_b = c4;
-                       num_bots_team_b = num_bots_team4;
-                       score_team_b = team4_score;
-                       break;
+                       TeamBalance_AutoBalanceBots(forced_team_index, old_team_index);
                }
+               return;
        }
-       // invalid
-       if (num_players_team_a < 0 || num_players_team_b < 0)
-               return false;
-
-       if (IS_REAL_CLIENT(player) && bots_would_leave)
+       int best_team_index = TeamBalance_FindBestTeam(balance, this, true);
+       TeamBalance_Destroy(balance);
+       PlayerScore_Clear(this);
+       if (!SetPlayerTeam(this, best_team_index, TEAM_CHANGE_AUTO))
        {
-               num_players_team_a -= num_bots_team_a;
-               num_players_team_b -= num_bots_team_b;
-       }
-       if (!use_score)
-       {
-               return num_players_team_a == num_players_team_b;
+               return;
        }
-       if (num_players_team_a != num_players_team_b)
+       if ((old_team_index != -1) && !IS_BOT_CLIENT(this))
        {
-               return false;
+               TeamBalance_AutoBalanceBots(best_team_index, old_team_index);
        }
-       return score_team_a == score_team_b;
 }
 
-int FindBestTeams(entity player, bool use_score)
+int TeamBalance_CompareTeams(entity balance, int team_index_a, int team_index_b,
+       entity player, bool use_score)
 {
-       if (MUTATOR_CALLHOOK(FindBestTeams, player) == true)
+       if (balance == NULL)
        {
-               return M_ARGV(1, float);
+               LOG_FATAL("TeamBalance_CompareTeams: Team balance entity is NULL.");
        }
-       int team_bits = 0;
-       int previous_team = 0;
-       if (c1 >= 0)
+       if (balance.m_team_balance_state != TEAM_BALANCE_TEAM_COUNTS_FILLED)
        {
-               team_bits = BIT(0);
-               previous_team = 1;
+               LOG_FATAL("TeamBalance_CompareTeams: "
+                       "TeamBalance_GetTeamCounts has not been called.");
        }
-       if (c2 >= 0)
+       if (!Team_IsValidIndex(team_index_a))
        {
-               if (previous_team == 0)
-               {
-                       team_bits = BIT(1);
-                       previous_team = 2;
-               }
-               else if (IsTeamSmallerThanTeam(2, previous_team, player, use_score))
-               {
-                       team_bits = BIT(1);
-                       previous_team = 2;
-               }
-               else if (IsTeamEqualToTeam(2, previous_team, player, use_score))
-               {
-                       team_bits |= BIT(1);
-                       previous_team = 2;
-               }
+               LOG_FATALF("TeamBalance_CompareTeams: team_index_a is invalid: %f",
+                       team_index_a);
        }
-       if (c3 >= 0)
+       if (!Team_IsValidIndex(team_index_b))
        {
-               if (previous_team == 0)
-               {
-                       team_bits = BIT(2);
-                       previous_team = 3;
-               }
-               else if (IsTeamSmallerThanTeam(3, previous_team, player, use_score))
-               {
-                       team_bits = BIT(2);
-                       previous_team = 3;
-               }
-               else if (IsTeamEqualToTeam(3, previous_team, player, use_score))
-               {
-                       team_bits |= BIT(2);
-                       previous_team = 3;
-               }
+               LOG_FATALF("TeamBalance_CompareTeams: team_index_b is invalid: %f",
+                       team_index_b);
        }
-       if (c4 >= 0)
+       if (team_index_a == team_index_b)
        {
-               if (previous_team == 0)
-               {
-                       team_bits = BIT(3);
-               }
-               else if (IsTeamSmallerThanTeam(4, previous_team, player, use_score))
-               {
-                       team_bits = BIT(3);
-               }
-               else if (IsTeamEqualToTeam(4, previous_team, player, use_score))
-               {
-                       team_bits |= BIT(3);
-               }
+               return TEAMS_COMPARE_EQUAL;
        }
-       return team_bits;
+       entity team_a = TeamBalance_GetTeamFromIndex(balance, team_index_a);
+       entity team_b = TeamBalance_GetTeamFromIndex(balance, team_index_b);
+       return TeamBalance_CompareTeamsInternal(team_a, team_b, player, use_score);
 }
 
-// returns # of smallest team (1, 2, 3, 4)
-// NOTE: Assumes CheckAllowedTeams has already been called!
-int FindSmallestTeam(entity player, float ignore_player)
+void TeamBalance_AutoBalanceBots(int source_team_index,
+       int destination_team_index)
 {
-       // count how many players are in each team
-       if (ignore_player)
+       if (!Team_IsValidIndex(source_team_index))
        {
-               GetTeamCounts(player);
+               LOG_WARNF("TeamBalance_AutoBalanceBots: "
+                       "Source team index is invalid: %f", source_team_index);
+               return;
        }
-       else
+       if (!Team_IsValidIndex(destination_team_index))
        {
-               GetTeamCounts(NULL);
+               LOG_WARNF("TeamBalance_AutoBalanceBots: "
+                       "Destination team index is invalid: %f", destination_team_index);
+               return;
        }
-       int team_bits = FindBestTeams(player, true);
-       if (team_bits == 0)
+       if (!autocvar_g_balance_teams ||
+               !autocvar_g_balance_teams_prevent_imbalance)
        {
-               error(sprintf("No teams available for %s\n", MapInfo_Type_ToString(MapInfo_CurrentGametype())));
+               return;
        }
-       RandomSelection_Init();
-       if ((team_bits & BIT(0)) != 0)
+       entity balance = TeamBalance_CheckAllowedTeams(NULL);
+       TeamBalance_GetTeamCounts(balance, NULL);
+       entity source_team = TeamBalance_GetTeamFromIndex(balance,
+               source_team_index);
+       entity destination_team = TeamBalance_GetTeamFromIndex(balance,
+               destination_team_index);
+       if ((source_team.m_num_bots == 0) || (source_team.m_num_players <=
+               destination_team.m_num_players))
        {
-               RandomSelection_AddFloat(1, 1, 1);
+               TeamBalance_Destroy(balance);
+               return;
        }
-       if ((team_bits & BIT(1)) != 0)
+       TeamBalance_Destroy(balance);
+       entity lowest_bot = NULL;
+       if (MUTATOR_CALLHOOK(TeamBalance_GetPlayerForTeamSwitch, source_team_index,
+               destination_team_index, true))
        {
-               RandomSelection_AddFloat(2, 1, 1);
+               lowest_bot = M_ARGV(3, entity);
        }
-       if ((team_bits & BIT(2)) != 0)
+       else
        {
-               RandomSelection_AddFloat(3, 1, 1);
+               float lowest_score = FLOAT_MAX;
+               FOREACH_CLIENT(IS_BOT_CLIENT(it) && (Entity_GetTeamIndex(it) ==
+                       source_team_index),
+               {
+                       float temp_score = PlayerScore_Get(it, SP_SCORE);
+                       if (temp_score >= lowest_score)
+                       {
+                               continue;
+                       }
+                       balance = TeamBalance_CheckAllowedTeams(it);
+                       if (TeamBalance_IsTeamAllowed(balance, destination_team_index))
+                       {
+                               lowest_bot = it;
+                               lowest_score = temp_score;
+                       }
+                       TeamBalance_Destroy(balance);
+               });
        }
-       if ((team_bits & BIT(3)) != 0)
+       if (lowest_bot == NULL)
        {
-               RandomSelection_AddFloat(4, 1, 1);
+               return;
        }
-       return RandomSelection_chosen_float;
-}
-
-void JoinBestTeam(entity this, bool force_best_team)
-{
-       // don't join a team if we're not playing a team game
-       if (!teamplay)
+       if (!Player_SetTeamIndex(lowest_bot, destination_team_index))
        {
                return;
        }
+       KillPlayerForTeamChange(lowest_bot);
+}
 
-       // find out what teams are available
-       CheckAllowedTeams(this);
+bool TeamBalance_IsTeamAllowedInternal(entity balance, int index)
+{
+       return balance.m_team_balance_team[index - 1].m_num_players !=
+               TEAM_NOT_ALLOWED;
+}
 
-       // if we don't care what team they end up on, put them on whatever team they entered as.
-       // if they're not on a valid team, then let other code put them on the smallest team
-       if (!force_best_team)
+void TeamBalance_BanTeamsExcept(entity balance, int index)
+{
+       for (int i = 1; i <= NUM_TEAMS; ++i)
        {
-               int selected_team;
-               if ((c1 >= 0) && (this.team == NUM_TEAM_1))
-               {
-                       selected_team = this.team;
-               }
-               else if ((c2 >= 0) && (this.team == NUM_TEAM_2))
-               {
-                       selected_team = this.team;
-               }
-               else if ((c3 >= 0) && (this.team == NUM_TEAM_3))
-               {
-                       selected_team = this.team;
-               }
-               else if ((c4 >= 0) && (this.team == NUM_TEAM_4))
-               {
-                       selected_team = this.team;
-               }
-               else
+               if (i != index)
                {
-                       selected_team = -1;
+                       balance.m_team_balance_team[i - 1].m_num_players = TEAM_NOT_ALLOWED;
                }
+       }
+}
 
-               if (selected_team > 0)
-               {
-                       SetPlayerTeamSimple(this, selected_team);
-                       LogTeamchange(this.playerid, this.team, 99);
-                       return;
-               }
+entity TeamBalance_GetTeamFromIndex(entity balance, int index)
+{
+       if (!Team_IsValidIndex(index))
+       {
+               LOG_FATALF("TeamBalance_GetTeamFromIndex: Index is invalid: %f", index);
        }
-       // otherwise end up on the smallest team (handled below)
-       if (this.bot_forced_team)
+       return balance.m_team_balance_team[index - 1];
+}
+
+entity TeamBalance_GetTeam(entity balance, int team_num)
+{
+       return TeamBalance_GetTeamFromIndex(balance, Team_TeamToIndex(team_num));
+}
+
+bool TeamBalanceTeam_IsAllowed(entity team_ent)
+{
+       return team_ent.m_num_players != TEAM_NOT_ALLOWED;
+}
+
+int TeamBalanceTeam_GetNumberOfPlayers(entity team_ent)
+{
+       return team_ent.m_num_players;
+}
+
+int TeamBalanceTeam_GetNumberOfBots(entity team_ent)
+{
+       return team_ent.m_num_bots;
+}
+
+int TeamBalance_CompareTeamsInternal(entity team_a, entity team_b,
+       entity player, bool use_score)
+{
+       if (team_a == team_b)
        {
-               return;
+               return TEAMS_COMPARE_EQUAL;
+       }
+       if (!TeamBalanceTeam_IsAllowed(team_a) ||
+               !TeamBalanceTeam_IsAllowed(team_b))
+       {
+               return TEAMS_COMPARE_INVALID;
        }
-       int best_team = FindSmallestTeam(this, true);
-       best_team = Team_NumberToTeam(best_team);
-       if (best_team == -1)
+       int num_players_team_a = team_a.m_num_players;
+       int num_players_team_b = team_b.m_num_players;
+       if (IS_REAL_CLIENT(player) && bots_would_leave)
+       {
+               num_players_team_a -= team_a.m_num_bots;
+               num_players_team_b -= team_b.m_num_bots;
+       }
+       if (num_players_team_a < num_players_team_b)
+       {
+               return TEAMS_COMPARE_LESS;
+       }
+       if (num_players_team_a > num_players_team_b)
+       {
+               return TEAMS_COMPARE_GREATER;
+       }
+       if (!use_score)
        {
-               error("JoinBestTeam: invalid team\n");
+               return TEAMS_COMPARE_EQUAL;
        }
-       int old_team = Team_TeamToNumber(this.team);
-       TeamchangeFrags(this);
-       SetPlayerTeamSimple(this, best_team);
-       LogTeamchange(this.playerid, this.team, 2); // log auto join
-       if ((old_team != -1) && !IS_BOT_CLIENT(this))
+       if (team_a.m_team_score < team_b.m_team_score)
        {
-               AutoBalanceBots(old_team, Team_TeamToNumber(best_team));
+               return TEAMS_COMPARE_LESS;
        }
-       KillPlayerForTeamChange(this);
+       if (team_a.m_team_score > team_b.m_team_score)
+       {
+               return TEAMS_COMPARE_GREATER;
+       }
+       return TEAMS_COMPARE_EQUAL;
 }
 
+// Called when the player connects or when they change their color with "color"
+// command.
 void SV_ChangeTeam(entity this, float _color)
 {
-       float source_color, destination_color, source_team, destination_team;
+       //PrintToChatAll(sprintf("SV_ChangeTeam: %s, %f", this.netname, _color));
 
        // in normal deathmatch we can just apply the color and we're done
        if(!teamplay)
@@ -933,28 +886,48 @@ void SV_ChangeTeam(entity this, float _color)
        if(!teamplay)
                return;
 
+       int source_color, destination_color;
+       int source_team_index, destination_team_index;
+
        source_color = this.clientcolors & 0x0F;
        destination_color = _color & 0x0F;
 
-       source_team = Team_TeamToNumber(source_color + 1);
-       destination_team = Team_TeamToNumber(destination_color + 1);
+       source_team_index = Team_TeamToIndex(source_color + 1);
+       destination_team_index = Team_TeamToIndex(destination_color + 1);
 
-       if (destination_team == -1)
+       if (destination_team_index == -1)
        {
                return;
        }
 
-       CheckAllowedTeams(this);
+       entity balance = TeamBalance_CheckAllowedTeams(this);
 
-       if (destination_team == 1 && c1 < 0) destination_team = 4;
-       if (destination_team == 4 && c4 < 0) destination_team = 3;
-       if (destination_team == 3 && c3 < 0) destination_team = 2;
-       if (destination_team == 2 && c2 < 0) destination_team = 1;
+       if (destination_team_index == 1 && !TeamBalance_IsTeamAllowedInternal(
+               balance, 1))
+       {
+               destination_team_index = 4;
+       }
+       if (destination_team_index == 4 && !TeamBalance_IsTeamAllowedInternal(
+               balance, 4))
+       {
+               destination_team_index = 3;
+       }
+       if (destination_team_index == 3 && !TeamBalance_IsTeamAllowedInternal(
+               balance, 3))
+       {
+               destination_team_index = 2;
+       }
+       if (destination_team_index == 2 && !TeamBalance_IsTeamAllowedInternal(
+               balance, 2))
+       {
+               destination_team_index = 1;
+       }
 
        // not changing teams
        if (source_color == destination_color)
        {
-               SetPlayerTeam(this, destination_team, source_team, true);
+               SetPlayerTeam(this, destination_team_index, TEAM_CHANGE_MANUAL);
+               TeamBalance_Destroy(balance);
                return;
        }
 
@@ -966,111 +939,28 @@ void SV_ChangeTeam(entity this, float _color)
        // autocvar_g_balance_teams_prevent_imbalance only makes sense if autocvar_g_balance_teams is on, as it makes the team selection dialog pointless
        if (autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance)
        {
-               GetTeamCounts(this);
-               if ((BIT(destination_team - 1) & FindBestTeams(this, false)) == 0)
+               TeamBalance_GetTeamCounts(balance, this);
+               if ((Team_IndexToBit(destination_team_index) &
+                       TeamBalance_FindBestTeams(balance, this, false)) == 0)
                {
                        Send_Notification(NOTIF_ONE, this, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM);
+                       TeamBalance_Destroy(balance);
                        return;
                }
        }
-       if(IS_PLAYER(this) && source_team != destination_team)
+       TeamBalance_Destroy(balance);
+       if (IS_PLAYER(this) && source_team_index != destination_team_index)
        {
                // reduce frags during a team change
-               TeamchangeFrags(this);
-       }
-       if (!SetPlayerTeam(this, destination_team, source_team, !IS_CLIENT(this)))
-       {
-               return;
-       }
-       AutoBalanceBots(source_team, destination_team);
-       if (!IS_PLAYER(this) || (source_team == destination_team))
-       {
-               return;
+               PlayerScore_Clear(this);
        }
-       KillPlayerForTeamChange(this);
-}
-
-void AutoBalanceBots(int source_team, int destination_team)
-{
-       if (!Team_IsValidNumber(source_team))
+       if (!SetPlayerTeam(this, destination_team_index, TEAM_CHANGE_MANUAL))
        {
-               LOG_WARNF("AutoBalanceBots: Source team is invalid: %f", source_team);
                return;
        }
-       if (!Team_IsValidNumber(destination_team))
-       {
-               LOG_WARNF("AutoBalanceBots: Destination team is invalid: %f",
-                       destination_team);
-               return;
-       }
-       if (!autocvar_g_balance_teams ||
-               !autocvar_g_balance_teams_prevent_imbalance)
-       {
-               return;
-       }
-       int num_players_source_team = 0;
-       int num_players_destination_team = 0;
-       entity lowest_bot_destination_team = NULL;
-       switch (source_team)
-       {
-               case 1:
-               {
-                       num_players_source_team = c1;
-                       break;
-               }
-               case 2:
-               {
-                       num_players_source_team = c2;
-                       break;
-               }
-               case 3:
-               {
-                       num_players_source_team = c3;
-                       break;
-               }
-               case 4:
-               {
-                       num_players_source_team = c4;
-                       break;
-               }
-       }
-       if (num_players_source_team < 0)
-       {
-               return;
-       }
-       switch (destination_team)
-       {
-               case 1:
-               {
-                       num_players_destination_team = c1;
-                       lowest_bot_destination_team = lowest_bot_team1;
-                       break;
-               }
-               case 2:
-               {
-                       num_players_destination_team = c2;
-                       lowest_bot_destination_team = lowest_bot_team2;
-                       break;
-               }
-               case 3:
-               {
-                       num_players_destination_team = c3;
-                       lowest_bot_destination_team = lowest_bot_team3;
-                       break;
-               }
-               case 4:
-               {
-                       num_players_destination_team = c4;
-                       lowest_bot_destination_team = lowest_bot_team4;
-                       break;
-               }
-       }
-       if ((num_players_destination_team <= num_players_source_team) ||
-               (lowest_bot_destination_team == NULL))
+       if (source_team_index == -1)
        {
                return;
        }
-       SetPlayerTeamSimple(lowest_bot_destination_team,
-               Team_NumberToTeam(source_team));
-       KillPlayerForTeamChange(lowest_bot_destination_team);
+       TeamBalance_AutoBalanceBots(destination_team_index, source_team_index);
 }
index 7c4ebe77b6c2a82a51ae2949999734d5da4022e8..776a80d329cf91d5917f1af4e1ba7275eb18a731 100644 (file)
 #pragma once
 
-string cache_mutatormsg;
-string cache_lastmutatormsg;
+bool lockteams;
 
-// The following variables are used for balancing. They are not updated
-// automatically. You need to call CheckAllowedTeams and GetTeamCounts to get
-// proper values.
+// ========================== Global teams API ================================
 
-// These four have 2 different states. If they are equal to -1, it means that
-// the player can't join the team. Zero or positive value means that player can
-// join the team and means the number of players on that team.
-float c1;
-float c2;
-float c3;
-float c4;
-float num_bots_team1; ///< Number of bots in the first team.
-float num_bots_team2; ///< Number of bots in the second team.
-float num_bots_team3; ///< Number of bots in the third team.
-float num_bots_team4; ///< Number of bots in the fourth team.
-entity lowest_human_team1; ///< Human with the lowest score in the first team.
-entity lowest_human_team2; ///< Human with the lowest score in the second team.
-entity lowest_human_team3; ///< Human with the lowest score in the third team.
-entity lowest_human_team4; ///< Human with the lowest score in the fourth team.
-entity lowest_bot_team1; ///< Bot with the lowest score in the first team.
-entity lowest_bot_team2; ///< Bot with the lowest score in the second team.
-entity lowest_bot_team3; ///< Bot with the lowest score in the third team.
-entity lowest_bot_team4; ///< Bot with the lowest score in the fourth team.
+/// \brief Returns the global team entity at the given index.
+/// \param[in] index Index of the team.
+/// \return Global team entity at the given index.
+entity Team_GetTeamFromIndex(int index);
 
-int redowned, blueowned, yellowowned, pinkowned;
+/// \brief Returns the global team entity that corresponds to the given TEAM_NUM
+/// value.
+/// \param[in] team_num Team value. See TEAM_NUM constants.
+/// \return Global team entity that corresponds to the given TEAM_NUM value.
+entity Team_GetTeam(int team_num);
 
-//float audit_teams_time;
+// ========================= Team specific API ================================
 
-void TeamchangeFrags(entity e);
+/// \brief Returns the score of the team.
+/// \param[in] team_ent Team entity.
+/// \return Score of the team.
+float Team_GetTeamScore(entity team_ent);
 
-void LogTeamchange(float player_id, float team_number, float type);
+/// \brief Sets the score of the team.
+/// \param[in,out] team_ent Team entity.
+/// \param[in] score Score to set.
+void Team_SetTeamScore(entity team_ent, float score);
 
-void default_delayedinit(entity this);
+/// \brief Returns the number of alive players in a team.
+/// \param[in] team_ent Team entity.
+/// \return Number of alive players in a team.
+int Team_GetNumberOfAlivePlayers(entity team_ent);
 
-void InitGameplayMode();
+/// \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);
 
-string GetClientVersionMessage(entity this);
+/// \brief Returns the number of alive teams.
+/// \return Number of alive teams.
+int Team_GetNumberOfAliveTeams();
 
-string getwelcomemessage(entity this);
+/// \brief Returns the number of control points owned by a team.
+/// \param[in] team_ent Team entity.
+/// \return Number of control points owned by a team.
+int Team_GetNumberOfControlPoints(entity team_ent);
 
-void SetPlayerColors(entity player, float _color);
+/// \brief Sets the number of control points owned by a team.
+/// \param[in,out] team_ent Team entity.
+/// \param[in] number Number of control points to set.
+void Team_SetNumberOfControlPoints(entity team_ent, int number);
 
-/// \brief Kills player as a result of team change.
-/// \param[in,out] player Player to kill.
-/// \return No return.
-void KillPlayerForTeamChange(entity player);
+/// \brief Returns the number of teams that own control points.
+/// \return Number of teams that own control points.
+int Team_GetNumberOfTeamsWithControlPoints();
 
-/// \brief Sets the team of the player.
+// ======================= Entity specific API ================================
+
+void setcolor(entity this, int clr);
+
+/// \brief Returns whether the given entity belongs to a valid team.
+/// \param[in] this Entity to check.
+/// \return True if entity belongs to a valid team, false otherwise.
+bool Entity_HasValidTeam(entity this);
+
+/// \brief Returns the team index of the given entity.
+/// \param[in] this Entity to check.
+/// \return Team index of the entity.
+int Entity_GetTeamIndex(entity this);
+
+/// \brief Returns the team entity of the given entity.
+/// \param[in] this Entity to check.
+/// \return Team entity of the given entity or NULL if the entity doesn't belong
+/// to any team.
+entity Entity_GetTeam(entity this);
+
+void SetPlayerColors(entity player, float _color);
+
+/// \brief Sets the team of the player using its index.
 /// \param[in,out] player Player to adjust.
-/// \param[in] team_num Team number to set. See TEAM_NUM constants.
+/// \param[in] index Index of the team to set.
 /// \return True if team switch was successful, false otherwise.
-bool SetPlayerTeamSimple(entity player, int team_num);
+bool Player_SetTeamIndex(entity player, int index);
 
 /// \brief Sets the team of the player.
 /// \param[in,out] player Player to adjust.
-/// \param[in] destination_team Team to set.
-/// \param[in] source_team Previous team of the player.
-/// \param[in] no_print Whether to print this event to players' console.
+/// \param[in] team_index Index of the team to set.
+/// \param[in] type ???
 /// \return True if team switch was successful, false otherwise.
-bool SetPlayerTeam(entity player, int destination_team, int source_team,
-       bool no_print);
+bool SetPlayerTeam(entity player, int team_index, int type);
+
+/// \brief Moves player to the specified team.
+/// \param[in,out] client Client to move.
+/// \param[in] team_index Index of the team.
+/// \param[in] type ???
+/// \return True on success, false otherwise.
+bool MoveToTeam(entity client, int team_index, int type);
+
+/// \brief Kills player as a result of team change.
+/// \param[in,out] player Player to kill.
+void KillPlayerForTeamChange(entity player);
 
-// set c1...c4 to show what teams are allowed
-void CheckAllowedTeams(entity for_whom);
+enum
+{
+       TEAM_CHANGE_AUTO = 2,
+       TEAM_CHANGE_MANUAL = 3,
+       TEAM_CHANGE_SPECTATOR = 4
+};
 
-float PlayerValue(entity p);
+void LogTeamchange(float player_id, float team_number, int type);
 
-// c1...c4 should be set to -1 (not allowed) or 0 (allowed).
-// teams that are allowed will now have their player counts stored in c1...c4
-void GetTeamCounts(entity ignore);
+// ========================= Team balance API =================================
 
-/// \brief Returns whether one team is smaller than the other.
-/// \param[in] team_a First team.
-/// \param[in] team_b Second team.
+/// \brief Checks whether the player can join teams according to global
+/// configuration and mutator settings.
+/// \param[in] for_whom Player to check for. Pass NULL for global rules.
+/// \return Team balance entity that holds information about teams. This entity
+/// will be automatically destroyed on the next frame but you are encouraged to
+/// manually destroy it by calling TeamBalance_Destroy for performance reasons.
+entity TeamBalance_CheckAllowedTeams(entity for_whom);
+
+/// \brief Destroy the team balance entity.
+/// \param[in,out] balance Team balance entity to destroy.
+/// \note Team balance entity is allowed to be NULL.
+void TeamBalance_Destroy(entity balance);
+
+/// \brief Returns the bitmask of allowed teams.
+/// \param[in] balance Team balance entity.
+/// \return Bitmask of allowed teams.
+int TeamBalance_GetAllowedTeams(entity balance);
+
+/// \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.
+/// \return True if team change to the specified team is allowed, false
+/// otherwise.
+bool TeamBalance_IsTeamAllowed(entity balance, int index);
+
+/// \brief Counts the number of players and various other information about
+/// each team.
+/// \param[in,out] balance Team balance entity.
+/// \param[in] ignore Player to ignore. This is useful if you plan to switch the
+/// player's team. Pass NULL for global information.
+/// \note This function updates the internal state of the team balance entity.
+void TeamBalance_GetTeamCounts(entity balance, entity ignore);
+
+/// \brief Returns the number of players (both humans and bots) in a team.
+/// \param[in] balance Team balance entity.
+/// \param[in] index Index of the team.
+/// \return Number of player (both humans and bots) in a team.
+/// \note You need to call TeamBalance_GetTeamCounts before calling this
+/// function.
+int TeamBalance_GetNumberOfPlayers(entity balance, int index);
+
+/// \brief Finds the team that will make the game most balanced if the player
+/// joins it.
+/// \param[in] balance Team balance entity.
 /// \param[in] player Player to check.
-/// \param[in] use_score Whether to take into account team scores.
-/// \return True if first team is smaller than the second one, false otherwise.
-/// \note This function assumes that CheckAllowedTeams and GetTeamCounts have
-/// been called.
-bool IsTeamSmallerThanTeam(int team_a, int team_b, entity player,
-       bool use_score);
+/// \param[in] ignore_player ???
+/// \return Index of the team that will make the game most balanced if the
+/// player joins it. If there are several equally good teams available, the
+/// function will pick a random one.
+int TeamBalance_FindBestTeam(entity balance, entity player, bool ignore_player);
 
-/// \brief Returns whether one team is equal to the other.
-/// \param[in] team_a First team.
-/// \param[in] team_b Second team.
+/// \brief Returns the bitmask of the teams that will make the game most
+/// balanced if the player joins any of them.
+/// \param[in] balance Team balance entity.
 /// \param[in] player Player to check.
 /// \param[in] use_score Whether to take into account team scores.
-/// \return True if first team is equal to the second one, false otherwise.
-/// \note This function assumes that CheckAllowedTeams and GetTeamCounts have
-/// been called.
-bool IsTeamEqualToTeam(int team_a, int team_b, entity player, bool use_score);
+/// \return Bitmask of the teams that will make the game most balanced if the
+/// player joins any of them.
+/// \note You need to call TeamBalance_GetTeamCounts before calling this
+/// function.
+int TeamBalance_FindBestTeams(entity balance, entity player, bool use_score);
+
+void TeamBalance_JoinBestTeam(entity this);
 
-/// \brief Returns the bitmask of the best teams for the player to join.
+/// \brief Describes the result of comparing teams.
+enum
+{
+       TEAMS_COMPARE_INVALID, ///< One or both teams are invalid.
+       TEAMS_COMPARE_LESS, ///< First team is less than the second one.
+       TEAMS_COMPARE_EQUAL, ///< Both teams are equal.
+       TEAMS_COMPARE_GREATER ///< First team the greater than the second one.
+};
+
+/// \brief Compares two teams for the purposes of game balance.
+/// \param[in] balance Team balance entity.
+/// \param[in] team_index_a Index of the first team.
+/// \param[in] team_index_b Index of the second team.
 /// \param[in] player Player to check.
 /// \param[in] use_score Whether to take into account team scores.
-/// \return Bitmask of the best teams for the player to join.
-/// \note This function assumes that CheckAllowedTeams and GetTeamCounts have
-/// been called.
-int FindBestTeams(entity player, bool use_score);
+/// \return TEAMS_COMPARE value. See above.
+/// \note You need to call TeamBalance_GetTeamCounts before calling this
+/// function.
+int TeamBalance_CompareTeams(entity balance, int team_index_a, int team_index_b,
+       entity player, bool use_score);
 
-// returns # of smallest team (1, 2, 3, 4)
-// NOTE: Assumes CheckAllowedTeams has already been called!
-int FindSmallestTeam(entity player, float ignore_player);
+/// \brief Switches a bot from one team to another if teams are not balanced.
+/// \param[in] source_team_index Index of the team to switch from.
+/// \param[in] destination_team_index Index of the team to switch to.
+void TeamBalance_AutoBalanceBots(int source_team_index,
+       int destination_team_index);
 
-void JoinBestTeam(entity this, bool force_best_team);
+// ============================ Internal API ==================================
 
-/// \brief Auto balances bots in teams after the player has changed team.
-/// \param[in] source_team Previous team of the player (1, 2, 3, 4).
-/// \param[in] destination_team Current team of the player (1, 2, 3, 4).
-/// \return No return.
-/// \note This function assumes that CheckAllowedTeams and GetTeamCounts have
-/// been called.
-void AutoBalanceBots(int source_team, int destination_team);
+/// \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.
+/// \return True if team change to the specified team is allowed, false
+/// otherwise.
+/// \note This function bypasses all the sanity checks.
+bool TeamBalance_IsTeamAllowedInternal(entity balance, int index);
 
-void setcolor(entity this, int clr);
+/// \brief Bans team change to all teams except the given one.
+/// \param[in,out] balance Team balance entity.
+/// \param[in] index Index of the team.
+void TeamBalance_BanTeamsExcept(entity balance, int index);
+
+/// \brief Returns the team entity of the team balance entity at the given
+/// index.
+/// \param[in] balance Team balance entity.
+/// \param[in] index Index of the team.
+/// \return Team entity of the team balance entity at the given index.
+entity TeamBalance_GetTeamFromIndex(entity balance, int index);
+
+/// \brief Returns the team entity of the team balance entity that corresponds
+/// to the given TEAM_NUM value.
+/// \param[in] balance Team balance entity.
+/// \param[in] team_num Team value. See TEAM_NUM constants.
+/// \return Team entity of the team balance entity that corresponds to the given
+/// TEAM_NUM value.
+entity TeamBalance_GetTeam(entity balance, int team_num);
+
+/// \brief Returns whether the team is allowed.
+/// \param[in] team_ent Team entity.
+/// \return True if team is allowed, false otherwise.
+bool TeamBalanceTeam_IsAllowed(entity team_ent);
+
+/// \brief Returns the number of players (both humans and bots) in a team.
+/// \param[in] team_ent Team entity.
+/// \return Number of player (both humans and bots) in a team.
+/// \note You need to call TeamBalance_GetTeamCounts before calling this
+/// function.
+int TeamBalanceTeam_GetNumberOfPlayers(entity team_ent);
+
+/// \brief Returns the number of bots in a team.
+/// \param[in] team_ent Team entity.
+/// \return Number of bots in a team.
+/// \note You need to call TeamBalance_GetTeamCounts before calling this
+/// function.
+int TeamBalanceTeam_GetNumberOfBots(entity team_ent);
+
+/// \brief Compares two teams for the purposes of game balance.
+/// \param[in] team_a First team.
+/// \param[in] team_b Second team.
+/// \param[in] player Player to check.
+/// \param[in] use_score Whether to take into account team scores.
+/// \return TEAMS_COMPARE value. See above.
+/// \note You need to call TeamBalance_GetTeamCounts before calling this
+/// function.
+int TeamBalance_CompareTeamsInternal(entity team_a, entity team_index_b,
+       entity player, bool use_score);
index c2a9c32acdef778fac3191045753e8ee80032c60..4af13e10228d101f414d61feae9ad9b4adb9b132 100644 (file)
@@ -240,7 +240,7 @@ float W_GetCycleWeapon(entity this, string weaponorder, float dir, float imp, fl
 
 void W_SwitchWeapon_Force(Player this, Weapon wep, .entity weaponentity)
 {
-    TC(Weapon, wep);
+       TC(Weapon, wep);
        this.(weaponentity).cnt = this.(weaponentity).m_switchweapon.m_id;
        this.(weaponentity).m_switchweapon = wep;
        this.(weaponentity).selectweapon = wep.m_id;
index ddf1ff26248066b0fa719c18ab543802fc866d4b..b023180a138b1a9cca08235f950e8e81d633b17b 100644 (file)
@@ -138,7 +138,7 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect
                ent.punchangle_x = recoil * -1;
 
        if (snd != SND_Null) {
-               sound (ent, chan, snd, (W_DualWielding(ent) ? VOL_BASE * 0.7 : VOL_BASE), ATTN_NORM);
+               sound(ent, chan, snd, (W_DualWielding(ent) ? VOL_BASE * 0.7 : VOL_BASE), ATTN_NORM);
                W_PlayStrengthSound(ent);
        }
 
index bf81f7044187d3ec532ea0f44ab968c328bf211f..2017e65a760792fd3d8f0db24603729a139e4cc5 100644 (file)
@@ -428,8 +428,8 @@ bool forbidWeaponUse(entity player)
 
 void W_WeaponFrame(Player actor, .entity weaponentity)
 {
-    TC(Player, actor);
-    TC(PlayerState, PS(actor));
+       TC(Player, actor);
+       TC(PlayerState, PS(actor));
        entity this = actor.(weaponentity);
        if (frametime) this.weapon_frametime = frametime;
 
@@ -595,8 +595,8 @@ void W_WeaponFrame(Player actor, .entity weaponentity)
 
                if (!block_weapon)
                {
-            Weapon e = this.m_weapon;
-            TC(Weapon, e);
+                       Weapon e = this.m_weapon;
+                       TC(Weapon, e);
                        if (w != WEP_Null)
                        {
                                e.wr_think(e, actor, weaponentity, button_atck | (button_atck2 << 1));
@@ -731,7 +731,7 @@ void W_ReloadedAndReady(Weapon thiswep, entity actor, .entity weaponentity, int
 
 void W_Reload(entity actor, .entity weaponentity, float sent_ammo_min, Sound sent_sound)
 {
-    TC(Sound, sent_sound);
+       TC(Sound, sent_sound);
        // set global values to work with
        entity this = actor.(weaponentity);
        Weapon e = this.m_weapon;
index 5ac5a1ec8ddbce6451b641424d456c54db1df56b..8517818d6406c902715a967507f55b6eed28e669 100644 (file)
@@ -771,17 +771,14 @@ r_cullentities_trace 0
 r_shadow_glossexact 1
 r_shadow_glossintensity 1
 
-// use fake light if map has no lightmaps
-r_fakelight 1
+// use slightly better lighting than r_fullbright if map has no lightmaps, and for fullbrightplayers
+r_fullbright_directed 1
 
 r_water_hideplayer 1 // hide your own feet/player model in refraction views, this way you don't see half of your body under water
 r_water_refractdistort 0.019
 
 set cl_rainsnow_maxdrawdist 2048
 
-// equalize looks better than fullbright
-r_equalize_entities_fullbright 1
-
 // safe font defaults
 r_font_hinting 1
 r_font_disable_freetype 0
index 13e38ebe049428928e1b4c57ce3f88125afb4df9..4898cb6afcae4c7e3aac4726d479fab8c3645536 100644 (file)
@@ -343,9 +343,9 @@ set g_maplist_votable_nodetail 0    "nodetail only shows total count instead of all
 set g_maplist_votable_abstain 0        "when 1, you can abstain from your vote"
 set g_maplist_votable_screenshot_dir "maps levelshots" "where to look for map screenshots"
 
-set sv_vote_gametype 0 "show a vote screen for gametypes before map vote screen"
+set sv_vote_gametype 1 "show a vote screen for gametypes before map vote screen"
 set sv_vote_gametype_keeptwotime 10 "show only 2 options after this amount of time during gametype vote screen"
-set sv_vote_gametype_options "dm tdm ctf"
+set sv_vote_gametype_options "dm tdm ctf" "Keep the identifiers short, otherwise you'll run into issues with too long alias names (max is 31 characters) when using sv_vote_gametype_hook_*"
 set sv_vote_gametype_timeout 20
 set sv_vote_gametype_default_current 1 "Keep the current gametype if no one votes"
 
@@ -440,6 +440,7 @@ set g_jetpack 0 "Jetpack mutator"
 set g_hitplots 0 "when set to 1, hitplots are stored by the server to provide a means of proving that a triggerbot was used"
 set g_hitplots_individuals "" "the individuals, by IP, that should have their hitplots recorded"
 
+// set it to 1 to "fix bot moveto command and routing... now all bots can get to their seats" (Nexuiz repo, commit 2c9873e6)
 set bot_navigation_ignoreplayers 0 // FIXME remove this once the issue is solved
 set bot_sound_monopoly 0 "when enabled, only bots can make any noise"