Remove the g_ prefix from some server code files and rename sv_main to main
authorMario <mario.mario@y7mail.com>
Sun, 2 Aug 2020 12:22:45 +0000 (22:22 +1000)
committerMario <mario.mario@y7mail.com>
Sun, 2 Aug 2020 12:22:45 +0000 (22:22 +1000)
78 files changed:
qcsrc/common/gamemodes/gamemode/assault/sv_assault.qc
qcsrc/common/gamemodes/gamemode/ctf/sv_ctf.qc
qcsrc/common/gamemodes/gamemode/cts/sv_cts.qc
qcsrc/common/gamemodes/gamemode/domination/sv_domination.qc
qcsrc/common/gamemodes/gamemode/invasion/sv_invasion.qc
qcsrc/common/gamemodes/gamemode/keepaway/sv_keepaway.qc
qcsrc/common/gamemodes/gamemode/keyhunt/sv_keyhunt.qc
qcsrc/common/gamemodes/gamemode/lms/sv_lms.qc
qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc
qcsrc/common/gamemodes/gamemode/race/sv_race.qc
qcsrc/common/mapobjects/func/breakable.qc
qcsrc/common/mapobjects/target/spawn.qc
qcsrc/common/mapobjects/teleporters.qc
qcsrc/common/mapobjects/trigger/jumppads.qc
qcsrc/common/monsters/monster.qh
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/mutators/mutator/breakablehook/sv_breakablehook.qc
qcsrc/common/mutators/mutator/buffs/sv_buffs.qc
qcsrc/common/notifications/all.qc
qcsrc/common/physics/player.qc
qcsrc/common/playerstats.qc
qcsrc/common/turrets/sv_turrets.qc
qcsrc/common/vehicles/sv_vehicles.qc
qcsrc/common/weapons/all.qc
qcsrc/common/weapons/weapon/shockwave.qc
qcsrc/server/_mod.inc
qcsrc/server/_mod.qh
qcsrc/server/anticheat.qc
qcsrc/server/bot/default/bot.qc
qcsrc/server/bot/default/havocbot/havocbot.qc
qcsrc/server/campaign.qc
qcsrc/server/cheats.qc
qcsrc/server/client.qc
qcsrc/server/clientkill.qc
qcsrc/server/command/cmd.qc
qcsrc/server/command/common.qc
qcsrc/server/command/common.qh
qcsrc/server/command/getreplies.qc
qcsrc/server/command/getreplies.qh
qcsrc/server/command/radarmap.qc
qcsrc/server/command/sv_cmd.qc
qcsrc/server/command/vote.qc
qcsrc/server/command/vote.qh
qcsrc/server/damage.qc [new file with mode: 0644]
qcsrc/server/damage.qh [new file with mode: 0644]
qcsrc/server/g_damage.qc [deleted file]
qcsrc/server/g_damage.qh [deleted file]
qcsrc/server/g_hook.qc [deleted file]
qcsrc/server/g_hook.qh [deleted file]
qcsrc/server/g_world.qc [deleted file]
qcsrc/server/g_world.qh [deleted file]
qcsrc/server/hook.qc [new file with mode: 0644]
qcsrc/server/hook.qh [new file with mode: 0644]
qcsrc/server/impulse.qc
qcsrc/server/items/items.qc
qcsrc/server/main.qc [new file with mode: 0644]
qcsrc/server/main.qh [new file with mode: 0644]
qcsrc/server/mapvoting.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/miscfunctions.qh
qcsrc/server/player.qc
qcsrc/server/portals.qc
qcsrc/server/race.qc
qcsrc/server/round_handler.qc
qcsrc/server/scores.qc
qcsrc/server/spawnpoints.qc
qcsrc/server/sv_main.qc [deleted file]
qcsrc/server/sv_main.qh [deleted file]
qcsrc/server/teamplay.qc
qcsrc/server/weapons/accuracy.qc
qcsrc/server/weapons/common.qc
qcsrc/server/weapons/hitplot.qc
qcsrc/server/weapons/throwing.qc
qcsrc/server/weapons/tracing.qc
qcsrc/server/weapons/weaponstats.qc
qcsrc/server/weapons/weaponsystem.qc
qcsrc/server/world.qc [new file with mode: 0644]
qcsrc/server/world.qh [new file with mode: 0644]

index 3915429..fcfcf32 100644 (file)
@@ -4,8 +4,8 @@
 #include <common/mapobjects/func/breakable.qh>
 #include <common/mapobjects/triggers.qh>
 #include <common/turrets/sv_turrets.qh>
-#include <server/g_damage.qh>
-#include <server/g_world.qh>
+#include <server/damage.qh>
+#include <server/world.qh>
 #include <server/spawnpoints.qh>
 
 .entity sprite;
index ec296a9..7e43666 100644 (file)
@@ -7,8 +7,8 @@
 #include <server/command/vote.qh>
 #include <server/client.qh>
 #include <server/gamelog.qh>
-#include <server/g_damage.qh>
-#include <server/g_world.qh>
+#include <server/damage.qh>
+#include <server/world.qh>
 #include <server/items/items.qh>
 #include <server/race.qh>
 #include <server/teamplay.qh>
@@ -2205,7 +2205,7 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerPreThink)
                WaypointSprite_UpdateHealth(player.wps_flagcarrier, healtharmor_maxdamage(GetResource(player, RES_HEALTH), GetResource(player, RES_ARMOR), autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id).x);
 }
 
-MUTATOR_HOOKFUNCTION(ctf, Damage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc
+MUTATOR_HOOKFUNCTION(ctf, Damage_Calculate) // for changing damage and force values that are applied to players in damage.qc
 {
        entity frag_attacker = M_ARGV(1, entity);
        entity frag_target = M_ARGV(2, entity);
@@ -2358,7 +2358,7 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerUseKey)
                                if(head != player && SAME_TEAM(head, player))
                                if(!head.speedrunning && !head.vehicle)
                                {
-                                       // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
+                                       // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in damage.qc)
                                        vector head_center = WarpZone_UnTransformOrigin(head, CENTER_OR_VIEWOFS(head));
                                        vector passer_center = CENTER_OR_VIEWOFS(player);
 
index 22d021c..1550c8e 100644 (file)
@@ -2,7 +2,7 @@
 
 #include <server/client.qh>
 #include <server/race.qh>
-#include <server/g_world.qh>
+#include <server/world.qh>
 #include <server/gamelog.qh>
 #include <server/items/spawning.qh>
 #include <server/weapons/common.qh>
index 410d07e..0a6ee79 100644 (file)
@@ -2,7 +2,7 @@
 
 #include <server/client.qh>
 #include <server/command/vote.qh>
-#include <server/g_damage.qh>
+#include <server/damage.qh>
 #include <server/gamelog.qh>
 #include <server/items/items.qh>
 #include <server/teamplay.qh>
index 09be394..d74c2df 100644 (file)
@@ -6,7 +6,7 @@
 #include <common/monsters/sv_monsters.qh>
 
 #include <server/bot/api.qh>
-#include <server/g_world.qh>
+#include <server/world.qh>
 #include <server/teamplay.qh>
 
 IntrusiveList g_invasion_roundends;
index 6ce13f2..dda6185 100644 (file)
@@ -3,7 +3,7 @@
 #include <common/effects/all.qh>
 #include <server/client.qh>
 #include <server/gamelog.qh>
-#include <server/g_damage.qh>
+#include <server/damage.qh>
 #include <server/items/items.qh>
 
 .entity ballcarried;
@@ -384,7 +384,7 @@ MUTATOR_HOOKFUNCTION(ka, PlayerUseKey)
        }
 }
 
-MUTATOR_HOOKFUNCTION(ka, Damage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc
+MUTATOR_HOOKFUNCTION(ka, Damage_Calculate) // for changing damage and force values that are applied to players in damage.qc
 {
        entity frag_attacker = M_ARGV(1, entity);
        entity frag_target = M_ARGV(2, entity);
index 5e098c6..d48c76f 100644 (file)
@@ -2,7 +2,7 @@
 
 #include <server/command/vote.qh>
 #include <server/gamelog.qh>
-#include <server/g_damage.qh>
+#include <server/damage.qh>
 #include <server/items/items.qh>
 #include <common/mapobjects/triggers.qh>
 
index a206fcb..1b7b527 100644 (file)
@@ -3,7 +3,7 @@
 #include <common/mutators/mutator/instagib/items.qh>
 #include <server/campaign.qh>
 #include <server/command/_mod.qh>
-#include <server/g_world.qh>
+#include <server/world.qh>
 #include <server/items/items.qh>
 
 int autocvar_g_lms_extra_lives;
index 6bb2387..375edaf 100644 (file)
@@ -4,7 +4,7 @@
 
 #include <server/bot/api.qh>
 #include <server/command/vote.qh>
-#include <server/g_damage.qh>
+#include <server/damage.qh>
 #include <server/items/items.qh>
 #include <common/mapobjects/defs.qh>
 #include <common/mapobjects/triggers.qh>
index f56353d..5c6e52f 100644 (file)
@@ -1,7 +1,7 @@
 #include "sv_race.qh"
 
 #include <server/client.qh>
-#include <server/g_world.qh>
+#include <server/world.qh>
 #include <server/gamelog.qh>
 #include <server/race.qh>
 #include <common/ent_cs.qh>
index 24d7139..4db6516 100644 (file)
@@ -1,7 +1,7 @@
 #include "breakable.qh"
 #ifdef SVQC
 
-#include <server/g_damage.qh>
+#include <server/damage.qh>
 #include <server/bot/api.qh>
 #include <common/csqcmodel_settings.qh>
 #include <lib/csqcmodel/sv_model.qh>
index 0c60793..b96370d 100644 (file)
@@ -5,7 +5,7 @@
     #include <common/util.qh>
     #include <common/weapons/_all.qh>
     #include <common/stats.qh>
-    #include <server/g_world.qh>
+    #include <server/world.qh>
 #endif
 
 #ifdef SVQC
index 24b7fb9..93bfcbb 100644 (file)
@@ -15,7 +15,7 @@
     #include <common/weapons/_all.qh>
     #include <common/stats.qh>
     #include "../deathtypes/all.qh"
-    #include <server/sv_main.qh>
+    #include <server/main.qh>
     #include "../turrets/sv_turrets.qh"
     #include "../vehicles/all.qh"
     #include <common/gamemodes/_mod.qh>
index 66a9499..5273179 100644 (file)
@@ -2,7 +2,7 @@
 // TODO: split target_push and put it in the target folder
 #ifdef SVQC
 #include <common/physics/movetypes/movetypes.qh>
-#include <server/sv_main.qh>
+#include <server/main.qh>
 
 void trigger_push_use(entity this, entity actor, entity trigger)
 {
index 146f64d..5d79c4a 100644 (file)
@@ -59,7 +59,7 @@ ENDCLASS(Monster)
 
 #ifdef SVQC
 #include "sv_monsters.qh"
-#include <server/g_damage.qh>
+#include <server/damage.qh>
 #include <server/bot/api.qh>
 #include <server/weapons/common.qh>
 #include <server/weapons/tracing.qh>
index 46bb159..d5bff8f 100644 (file)
 #include <server/autocvars.qh>
 #include <common/weapons/_all.qh>
 #include <common/stats.qh>
-#include <server/g_damage.qh>
+#include <server/damage.qh>
 #include "../deathtypes/all.qh"
 #include <server/items/items.qh>
 #include <server/mutators/_mod.qh>
 #include <server/steerlib.qh>
-#include <server/sv_main.qh>
+#include <server/main.qh>
 #include "../turrets/sv_turrets.qh"
 #include "../turrets/util.qh"
 #include "../vehicles/all.qh"
@@ -135,7 +135,7 @@ entity Monster_FindTarget(entity this)
        {
                if(Monster_ValidTarget(this, it))
                {
-                       // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
+                       // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in damage.qc)
                        vector targ_center = CENTER_OR_VIEWOFS(it);
 
                        if(closest_target)
index dc1bfef..c80b97d 100644 (file)
@@ -1,7 +1,7 @@
 #include "sv_breakablehook.qh"
 
 #include <common/deathtypes/all.qh>
-#include <server/g_hook.qh>
+#include <server/hook.qh>
 
 REGISTER_MUTATOR(breakablehook, cvar("g_breakablehook"));
 
index 29828a0..30cef33 100644 (file)
@@ -3,7 +3,7 @@
 #include <common/mapobjects/target/music.qh>
 #include <common/gamemodes/_mod.qh>
 #include <server/items/items.qh>
-#include <server/sv_main.qh>
+#include <server/main.qh>
 
 void buffs_DelayedInit(entity this);
 
index c8fb372..c46c217 100644 (file)
@@ -8,7 +8,7 @@
        #include <common/teams.qh>
        #include <server/autocvars.qh>
        #include <server/constants.qh>
-       #include <server/g_world.qh>
+       #include <server/world.qh>
        #include <server/mutators/_mod.qh>
 #endif
 
index af1ae0a..ade9c4d 100644 (file)
@@ -8,7 +8,7 @@
 #include <server/miscfunctions.qh>
 #include <common/mapobjects/defs.qh>
 #include "../mapobjects/trigger/viewloc.qh"
-#include <server/sv_main.qh>
+#include <server/main.qh>
 
 // client side physics
 bool Physics_Valid(string thecvar)
index d91e16f..3b8c97c 100644 (file)
@@ -9,7 +9,7 @@
     #include "../server/anticheat.qh"
     #include <common/stats.qh>
     #include "../server/scores.qh"
-       #include <server/g_world.qh>
+       #include <server/world.qh>
     #include "../server/weapons/accuracy.qh"
 #endif
 
@@ -296,7 +296,7 @@ void PlayerStats_GameReport_Handler(entity fh, entity pass, float status)
                 * G: game type
                 * O: mod name (icon request) as in server browser
                 * M: map name
-                * I: match ID (see "matchid" in g_world.qc)
+                * I: match ID (see "matchid" in world.qc)
                 * S: "hostname" of the server
                 * C: number of "unpure" cvar changes
                 * U: UDP port number of the server
index 84b0c82..e2a9ab2 100644 (file)
@@ -2,7 +2,7 @@
 #ifdef SVQC
 #include <server/autocvars.qh>
 #include <server/bot/api.qh>
-#include <server/g_damage.qh>
+#include <server/damage.qh>
 #include <server/weapons/common.qh>
 #include <server/weapons/weaponsystem.qh>
 #include <common/mapobjects/defs.qh>
index 590aba8..beff574 100644 (file)
@@ -1,14 +1,14 @@
 #include "sv_vehicles.qh"
 
 #include <server/bot/api.qh>
-#include <server/g_damage.qh>
-#include <server/g_world.qh>
+#include <server/damage.qh>
+#include <server/world.qh>
 #include <server/items/items.qh>
 #include <common/items/_mod.qh>
 #include <common/mapobjects/defs.qh>
 #include <common/mapobjects/teleporters.qh>
 #include <common/mapobjects/triggers.qh>
-#include <server/sv_main.qh>
+#include <server/main.qh>
 #include <server/weapons/common.qh>
 
 bool SendAuxiliaryXhair(entity this, entity to, int sf)
index 62e4ff0..dc87d6b 100644 (file)
@@ -41,7 +41,7 @@
     #include <server/command/_mod.qh>
     #include <lib/csqcmodel/sv_model.qh>
     #include <server/portals.qh>
-    #include <server/g_hook.qh>
+    #include <server/hook.qh>
 #endif
 #ifdef GAMEQC
        #include "calculations.qc"
index f38c34b..accb917 100644 (file)
@@ -479,7 +479,7 @@ void W_Shockwave_Attack(Weapon thiswep, entity actor, .entity weaponentity)
                        //  BLAST CONE CALCULATION
                        // ========================
 
-                       // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
+                       // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in damage.qc)
                        center = CENTER_OR_VIEWOFS(head);
 
                        // find the closest point on the enemy to the center of the attack
index 7634e76..0da2e2b 100644 (file)
@@ -5,13 +5,14 @@
 #include <server/cheats.qc>
 #include <server/client.qc>
 #include <server/clientkill.qc>
-#include <server/g_damage.qc>
-#include <server/g_hook.qc>
-#include <server/g_world.qc>
+#include <server/damage.qc>
+#include <server/hook.qc>
+#include <server/world.qc>
 #include <server/gamelog.qc>
 #include <server/handicap.qc>
 #include <server/impulse.qc>
 #include <server/ipban.qc>
+#include <server/main.qc>
 #include <server/mapvoting.qc>
 #include <server/matrix.qc>
 #include <server/miscfunctions.qc>
@@ -24,9 +25,6 @@
 #include <server/scores_rules.qc>
 #include <server/spawnpoints.qc>
 #include <server/steerlib.qc>
-#ifdef SVQC
-    #include <server/sv_main.qc>
-#endif
 #include <server/teamplay.qc>
 #include <server/tests.qc>
 
index 331fdcd..67080b3 100644 (file)
@@ -5,13 +5,14 @@
 #include <server/cheats.qh>
 #include <server/client.qh>
 #include <server/clientkill.qh>
-#include <server/g_damage.qh>
-#include <server/g_hook.qh>
-#include <server/g_world.qh>
+#include <server/damage.qh>
+#include <server/hook.qh>
+#include <server/world.qh>
 #include <server/gamelog.qh>
 #include <server/handicap.qh>
 #include <server/impulse.qh>
 #include <server/ipban.qh>
+#include <server/main.qh>
 #include <server/mapvoting.qh>
 #include <server/matrix.qh>
 #include <server/miscfunctions.qh>
@@ -24,9 +25,6 @@
 #include <server/scores_rules.qh>
 #include <server/spawnpoints.qh>
 #include <server/steerlib.qh>
-#ifdef SVQC
-    #include <server/sv_main.qh>
-#endif
 #include <server/teamplay.qh>
 #include <server/tests.qh>
 
index c0d1cc1..7e8e506 100644 (file)
@@ -6,7 +6,7 @@
 #include <common/stats.qh>
 #include <server/client.qh>
 #include <server/gamelog.qh>
-#include <server/sv_main.qh>
+#include <server/main.qh>
 #include "miscfunctions.qh"
 
 #include "command/common.qh"
index 9d526b7..e8f8102 100644 (file)
@@ -18,8 +18,8 @@
 #include "../../client.qh"
 #include "../../constants.qh"
 #include <common/stats.qh>
-#include <server/g_world.qh>
-#include <server/g_damage.qh>
+#include <server/world.qh>
+#include <server/damage.qh>
 #include "../../race.qh"
 #include <server/items/items.qh>
 
index f6917bd..40a07a4 100644 (file)
@@ -6,7 +6,7 @@
 #include <server/client.qh>
 #include <common/weapons/_all.qh>
 #include <common/stats.qh>
-#include <server/g_damage.qh>
+#include <server/damage.qh>
 #include <server/items/items.qh>
 #include <server/miscfunctions.qh>
 #include <server/weapons/selection.qh>
index 92d183a..de46e57 100644 (file)
@@ -5,7 +5,7 @@
 
 #include "cheats.qh"
 #include "miscfunctions.qh"
-#include "g_world.qh"
+#include "world.qh"
 
 #include "../common/campaign_common.qh"
 
index dc41fac..9d5cc1d 100644 (file)
@@ -5,9 +5,9 @@
 #include <server/miscfunctions.qh>
 #include <common/effects/all.qh>
 #include <server/resources.qh>
-#include <server/sv_main.qh>
+#include <server/main.qh>
 
-#include "g_damage.qh"
+#include "damage.qh"
 #include "clientkill.qh"
 #include "player.qh"
 #include "race.qh"
index 99aa86d..0a9a38f 100644 (file)
 #include "teamplay.qh"
 #include "spawnpoints.qh"
 #include "resources.qh"
-#include "g_damage.qh"
+#include "damage.qh"
 #include "handicap.qh"
-#include "g_hook.qh"
+#include "hook.qh"
 #include "command/common.qh"
 #include "command/vote.qh"
 #include "clientkill.qh"
 #include "cheats.qh"
-#include "g_world.qh"
+#include "world.qh"
 #include <server/gamelog.qh>
 #include "race.qh"
-#include <server/sv_main.qh>
+#include <server/main.qh>
 #include "antilag.qh"
 #include "campaign.qh"
 #include "command/common.qh"
index 600faed..73ccb38 100644 (file)
@@ -5,7 +5,7 @@
 #include <server/client.qh>
 #include <server/player.qh>
 
-#include "g_damage.qh"
+#include "damage.qh"
 #include "teamplay.qh"
 
 #include <common/vehicles/sv_vehicles.qh>
index 815c5e2..fe92d36 100644 (file)
@@ -1,6 +1,6 @@
 #include "cmd.qh"
 
-#include <server/g_world.qh>
+#include <server/world.qh>
 #include <server/miscfunctions.qh>
 
 #include <common/command/_mod.qh>
index 48f1cd1..0f59802 100644 (file)
@@ -3,7 +3,7 @@
 #include <server/client.qh>
 #include <common/weapons/_all.qh>
 #include <common/stats.qh>
-#include <server/g_world.qh>
+#include <server/world.qh>
 #include <server/miscfunctions.qh>
 
 #include <common/command/_mod.qh>
index ea3af54..c9aad4b 100644 (file)
@@ -54,7 +54,7 @@ float timeout_status;    // (values: 0, 1, 2) contains whether a timeout is not
 .float allowed_timeouts; // contains the number of allowed timeouts for each player
 .vector lastV_angle;     // used when pausing the game in order to force the player to keep his old view angle fixed
 
-// allow functions to be used in other code like g_world.qc and teamplay.qc
+// allow functions to be used in other code like world.qc and teamplay.qc
 void timeout_handler_think(entity this);
 
 // used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
index c5a26e8..3262974 100644 (file)
@@ -2,7 +2,7 @@
 
 #include <common/weapons/_all.qh>
 #include <common/stats.qh>
-#include <server/g_world.qh>
+#include <server/world.qh>
 #include <server/miscfunctions.qh>
 
 #include <common/command/_mod.qh>
@@ -22,7 +22,7 @@
 //  Last updated: December 30th, 2011
 // =========================================================
 
-// These strings are set usually during init in g_world.qc,
+// These strings are set usually during init in world.qc,
 // or also by some game modes or other functions manually,
 // and their purpose is to output information to clients
 // without using any extra processing time.
index 7b43607..3ababee 100644 (file)
@@ -13,7 +13,7 @@ const int LADDER_SIZE = 30; // ladder shows the top X players
 string top_uids[LADDER_SIZE];
 float top_scores[LADDER_SIZE];
 
-// allow functions to be used in other code like g_world.qc and race.qc
+// allow functions to be used in other code like world.qc and race.qc
 string getrecords(float page);
 string getrankings();
 string getladder();
index 7ec8eb6..6e73777 100644 (file)
@@ -4,7 +4,7 @@
 #include <common/command/_mod.qh>
 #include <common/mapobjects/triggers.qh>
 
-#include "../g_world.qh"
+#include "../world.qh"
 
 #include <common/util.qh>
 
index 034bd6c..7de740b 100644 (file)
@@ -13,7 +13,7 @@
 #include "../campaign.qh"
 #include "../client.qh"
 #include "../player.qh"
-#include "../g_world.qh"
+#include "../world.qh"
 #include "../ipban.qh"
 #include "../teamplay.qh"
 
index 2ad5c05..ee8a8e8 100644 (file)
@@ -11,8 +11,8 @@
 
 #include "common.qh"
 
-#include "../g_damage.qh"
-#include "../g_world.qh"
+#include "../damage.qh"
+#include "../world.qh"
 #include "../teamplay.qh"
 #include "../race.qh"
 #include "../round_handler.qh"
index 55068ab..7085ca0 100644 (file)
@@ -38,7 +38,7 @@ string vote_called_display; // visual string of command sent by client
 string vote_parsed_command; // command which is fixed after being parsed
 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
+// allow functions to be used in other code like world.qc and teamplay.qc
 void VoteThink();
 void VoteReset();
 void VoteCommand(int request, entity caller, int argc, string vote_command);
diff --git a/qcsrc/server/damage.qc b/qcsrc/server/damage.qc
new file mode 100644 (file)
index 0000000..f799e96
--- /dev/null
@@ -0,0 +1,1301 @@
+#include "damage.qh"
+
+#include <common/effects/all.qh>
+#include "bot/api.qh"
+#include "hook.qh"
+#include <server/client.qh>
+#include <server/gamelog.qh>
+#include <server/items/items.qh>
+#include <server/mutators/_mod.qh>
+#include <server/main.qh>
+#include "teamplay.qh"
+#include "scores.qh"
+#include "spawnpoints.qh"
+#include "../common/state.qh"
+#include "../common/physics/player.qh"
+#include "resources.qh"
+#include "../common/vehicles/all.qh"
+#include "../common/items/_mod.qh"
+#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
+#include "../common/mutators/mutator/instagib/sv_instagib.qh"
+#include "../common/mutators/mutator/buffs/buffs.qh"
+#include "weapons/accuracy.qh"
+#include "weapons/csqcprojectile.qh"
+#include "weapons/selection.qh"
+#include "../common/constants.qh"
+#include "../common/deathtypes/all.qh"
+#include <common/mapobjects/defs.qh>
+#include <common/mapobjects/triggers.qh>
+#include "../common/notifications/all.qh"
+#include "../common/physics/movetypes/movetypes.qh"
+#include "../common/playerstats.qh"
+#include "../common/teams.qh"
+#include "../common/util.qh"
+#include <common/gamemodes/_mod.qh>
+#include <common/gamemodes/rules.qh>
+#include <common/weapons/_all.qh>
+#include "../lib/csqcmodel/sv_model.qh"
+#include "../lib/warpzone/common.qh"
+
+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)
+{
+       // TODO route through PlayerScores instead
+       if(game_stopped) return;
+
+       if(f < 0)
+       {
+               if(targ == attacker)
+               {
+                       // suicide
+                       GameRules_scoring_add(attacker, SUICIDES, 1);
+               }
+               else
+               {
+                       // teamkill
+                       GameRules_scoring_add(attacker, TEAMKILLS, 1);
+               }
+       }
+       else
+       {
+               // regular frag
+               GameRules_scoring_add(attacker, KILLS, 1);
+               if(!warmup_stage && targ.playerid)
+                       PlayerStats_GameReport_Event_Player(attacker, sprintf("kills-%d", targ.playerid), 1);
+       }
+
+       GameRules_scoring_add(targ, DEATHS, 1);
+
+       // FIXME fix the mess this is (we have REAL points now!)
+       if(MUTATOR_CALLHOOK(GiveFragsForKill, attacker, targ, f, deathtype, attacker.(weaponentity)))
+               f = M_ARGV(2, float);
+
+       attacker.totalfrags += f;
+
+       if(f)
+               UpdateFrags(attacker, f);
+}
+
+string AppendItemcodes(string s, entity player)
+{
+       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+       {
+               .entity weaponentity = weaponentities[slot];
+               int w = player.(weaponentity).m_weapon.m_id;
+               if(w == 0)
+                       w = player.(weaponentity).cnt; // previous weapon
+               if(w != 0 || slot == 0)
+                       s = strcat(s, ftos(w));
+       }
+       if(time < STAT(STRENGTH_FINISHED, player))
+               s = strcat(s, "S");
+       if(time < STAT(INVINCIBLE_FINISHED, player))
+               s = strcat(s, "I");
+       if(PHYS_INPUT_BUTTON_CHAT(player))
+               s = strcat(s, "T");
+       // TODO: include these codes as a flag on the item itself
+       MUTATOR_CALLHOOK(LogDeath_AppendItemCodes, player, s);
+       s = M_ARGV(1, string);
+       return s;
+}
+
+void LogDeath(string mode, int deathtype, entity killer, entity killed)
+{
+       string s;
+       if(!autocvar_sv_eventlog)
+               return;
+       s = strcat(":kill:", mode);
+       s = strcat(s, ":", ftos(killer.playerid));
+       s = strcat(s, ":", ftos(killed.playerid));
+       s = strcat(s, ":type=", Deathtype_Name(deathtype));
+       s = strcat(s, ":items=");
+       s = AppendItemcodes(s, killer);
+       if(killed != killer)
+       {
+               s = strcat(s, ":victimitems=");
+               s = AppendItemcodes(s, killed);
+       }
+       GameLogEcho(s);
+}
+
+void Obituary_SpecialDeath(
+       entity notif_target,
+       float murder,
+       int deathtype,
+       string s1, string s2, string s3,
+       float f1, float f2, float f3)
+{
+       if(!DEATH_ISSPECIAL(deathtype))
+       {
+               backtrace("Obituary_SpecialDeath called without a special deathtype?\n");
+               return;
+       }
+
+       entity deathent = REGISTRY_GET(Deathtypes, deathtype - DT_FIRST);
+       if (!deathent)
+       {
+               backtrace("Obituary_SpecialDeath: Could not find deathtype entity!\n");
+               return;
+       }
+
+       if(g_cts && deathtype == DEATH_KILL.m_id)
+               return; // TODO: somehow put this in CTS gamemode file!
+
+       Notification death_message = (murder) ? deathent.death_msgmurder : deathent.death_msgself;
+       if(death_message)
+       {
+               Send_Notification_WOCOVA(
+                       NOTIF_ONE,
+                       notif_target,
+                       MSG_MULTI,
+                       death_message,
+                       s1, s2, s3, "",
+                       f1, f2, f3, 0
+               );
+               Send_Notification_WOCOVA(
+                       NOTIF_ALL_EXCEPT,
+                       notif_target,
+                       MSG_INFO,
+                       death_message.nent_msginfo,
+                       s1, s2, s3, "",
+                       f1, f2, f3, 0
+               );
+       }
+}
+
+float Obituary_WeaponDeath(
+       entity notif_target,
+       float murder,
+       int deathtype,
+       string s1, string s2, string s3,
+       float f1, float f2)
+{
+       Weapon death_weapon = DEATH_WEAPONOF(deathtype);
+       if (death_weapon == WEP_Null)
+               return false;
+
+       w_deathtype = deathtype;
+       Notification death_message = ((murder) ? death_weapon.wr_killmessage(death_weapon) : death_weapon.wr_suicidemessage(death_weapon));
+       w_deathtype = false;
+
+       if (death_message)
+       {
+               Send_Notification_WOCOVA(
+                       NOTIF_ONE,
+                       notif_target,
+                       MSG_MULTI,
+                       death_message,
+                       s1, s2, s3, "",
+                       f1, f2, 0, 0
+               );
+               // send the info part to everyone
+               Send_Notification_WOCOVA(
+                       NOTIF_ALL_EXCEPT,
+                       notif_target,
+                       MSG_INFO,
+                       death_message.nent_msginfo,
+                       s1, s2, s3, "",
+                       f1, f2, 0, 0
+               );
+       }
+       else
+       {
+               LOG_TRACEF(
+                       "Obituary_WeaponDeath(): ^1Deathtype ^7(%d)^1 has no notification for weapon %s!\n",
+                       deathtype,
+                       death_weapon.netname
+               );
+       }
+
+       return true;
+}
+
+bool frag_centermessage_override(entity attacker, entity targ, int deathtype, int kill_count_to_attacker, int kill_count_to_target, string attacker_name)
+{
+       if(deathtype == DEATH_FIRE.m_id)
+       {
+               Send_Notification(NOTIF_ONE, attacker, MSG_CHOICE, CHOICE_FRAG_FIRE, targ.netname, kill_count_to_attacker, (IS_BOT_CLIENT(targ) ? -1 : CS(targ).ping));
+               Send_Notification(NOTIF_ONE, targ, MSG_CHOICE, CHOICE_FRAGGED_FIRE, attacker_name, kill_count_to_target, GetResource(attacker, RES_HEALTH), GetResource(attacker, RES_ARMOR), (IS_BOT_CLIENT(attacker) ? -1 : CS(attacker).ping));
+               return true;
+       }
+
+       return MUTATOR_CALLHOOK(FragCenterMessage, attacker, targ, deathtype, kill_count_to_attacker, kill_count_to_target);
+}
+
+void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .entity weaponentity)
+{
+       // Sanity check
+       if (!IS_PLAYER(targ)) { backtrace("Obituary called on non-player?!\n"); return; }
+
+       // Declarations
+       float notif_firstblood = false;
+       float kill_count_to_attacker, kill_count_to_target;
+       bool notif_anonymous = false;
+       string attacker_name = attacker.netname;
+
+       // Set final information for the death
+       targ.death_origin = targ.origin;
+       string deathlocation = (autocvar_notification_server_allows_location ? NearestLocation(targ.death_origin) : "");
+
+       // Abort now if a mutator requests it
+       if (MUTATOR_CALLHOOK(ClientObituary, inflictor, attacker, targ, deathtype, attacker.(weaponentity))) { CS(targ).killcount = 0; return; }
+       notif_anonymous = M_ARGV(5, bool);
+
+       if(notif_anonymous)
+               attacker_name = "Anonymous player";
+
+       #ifdef NOTIFICATIONS_DEBUG
+       Debug_Notification(
+               sprintf(
+                       "Obituary(%s, %s, %s, %s = %d);\n",
+                       attacker_name,
+                       inflictor.netname,
+                       targ.netname,
+                       Deathtype_Name(deathtype),
+                       deathtype
+               )
+       );
+       #endif
+
+       // =======
+       // SUICIDE
+       // =======
+       if(targ == attacker)
+       {
+               if(DEATH_ISSPECIAL(deathtype))
+               {
+                       if(deathtype == DEATH_TEAMCHANGE.m_id || deathtype == DEATH_AUTOTEAMCHANGE.m_id)
+                       {
+                               Obituary_SpecialDeath(targ, false, deathtype, targ.netname, deathlocation, "", targ.team, 0, 0);
+                       }
+                       else
+                       {
+                               switch(DEATH_ENT(deathtype))
+                               {
+                                       case DEATH_MIRRORDAMAGE:
+                                       {
+                                               Obituary_SpecialDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0, 0);
+                                               break;
+                                       }
+
+                                       default:
+                                       {
+                                               Obituary_SpecialDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0, 0);
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               else if (!Obituary_WeaponDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0))
+               {
+                       backtrace("SUICIDE: what the hell happened here?\n");
+                       return;
+               }
+               LogDeath("suicide", deathtype, targ, targ);
+               if(deathtype != DEATH_AUTOTEAMCHANGE.m_id) // special case: don't negate frags if auto switched
+                       GiveFrags(attacker, targ, -1, deathtype, weaponentity);
+       }
+
+       // ======
+       // MURDER
+       // ======
+       else if(IS_PLAYER(attacker))
+       {
+               if(SAME_TEAM(attacker, targ))
+               {
+                       LogDeath("tk", deathtype, attacker, targ);
+                       GiveFrags(attacker, targ, -1, deathtype, weaponentity);
+
+                       CS(attacker).killcount = 0;
+
+                       Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAG, targ.netname);
+                       Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAGGED, attacker_name);
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(targ.team, INFO_DEATH_TEAMKILL), targ.netname, attacker_name, deathlocation, CS(targ).killcount);
+
+                       // In this case, the death message will ALWAYS be "foo was betrayed by bar"
+                       // No need for specific death/weapon messages...
+               }
+               else
+               {
+                       LogDeath("frag", deathtype, attacker, targ);
+                       GiveFrags(attacker, targ, 1, deathtype, weaponentity);
+
+                       CS(attacker).taunt_soundtime = time + 1;
+                       CS(attacker).killcount = CS(attacker).killcount + 1;
+
+                       attacker.killsound += 1;
+
+                       // TODO: improve SPREE_ITEM and KILL_SPREE_LIST
+                       // these 2 macros are spread over multiple files
+                       #define SPREE_ITEM(counta,countb,center,normal,gentle) \
+                               case counta: \
+                                       Send_Notification(NOTIF_ONE, attacker, MSG_ANNCE, ANNCE_KILLSTREAK_##countb); \
+                                       if (!warmup_stage) \
+                                               PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
+                                       break;
+
+                       switch(CS(attacker).killcount)
+                       {
+                               KILL_SPREE_LIST
+                               default: break;
+                       }
+                       #undef SPREE_ITEM
+
+                       if(!warmup_stage && !checkrules_firstblood)
+                       {
+                               checkrules_firstblood = true;
+                               notif_firstblood = true; // modify the current messages so that they too show firstblood information
+                               PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
+                               PlayerStats_GameReport_Event_Player(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
+
+                               // tell spree_inf and spree_cen that this is a first-blood and first-victim event
+                               kill_count_to_attacker = -1;
+                               kill_count_to_target = -2;
+                       }
+                       else
+                       {
+                               kill_count_to_attacker = CS(attacker).killcount;
+                               kill_count_to_target = 0;
+                       }
+
+                       if(targ.istypefrag)
+                       {
+                               Send_Notification(
+                                       NOTIF_ONE,
+                                       attacker,
+                                       MSG_CHOICE,
+                                       CHOICE_TYPEFRAG,
+                                       targ.netname,
+                                       kill_count_to_attacker,
+                                       (IS_BOT_CLIENT(targ) ? -1 : CS(targ).ping)
+                               );
+                               Send_Notification(
+                                       NOTIF_ONE,
+                                       targ,
+                                       MSG_CHOICE,
+                                       CHOICE_TYPEFRAGGED,
+                                       attacker_name,
+                                       kill_count_to_target,
+                                       GetResource(attacker, RES_HEALTH),
+                                       GetResource(attacker, RES_ARMOR),
+                                       (IS_BOT_CLIENT(attacker) ? -1 : CS(attacker).ping)
+                               );
+                       }
+                       else if(!frag_centermessage_override(attacker, targ, deathtype, kill_count_to_attacker, kill_count_to_target, attacker_name))
+                       {
+                               Send_Notification(
+                                       NOTIF_ONE,
+                                       attacker,
+                                       MSG_CHOICE,
+                                       CHOICE_FRAG,
+                                       targ.netname,
+                                       kill_count_to_attacker,
+                                       (IS_BOT_CLIENT(targ) ? -1 : CS(targ).ping)
+                               );
+                               Send_Notification(
+                                       NOTIF_ONE,
+                                       targ,
+                                       MSG_CHOICE,
+                                       CHOICE_FRAGGED,
+                                       attacker_name,
+                                       kill_count_to_target,
+                                       GetResource(attacker, RES_HEALTH),
+                                       GetResource(attacker, RES_ARMOR),
+                                       (IS_BOT_CLIENT(attacker) ? -1 : CS(attacker).ping)
+                               );
+                       }
+
+                       int f3 = 0;
+                       if(deathtype == DEATH_BUFF.m_id)
+                               f3 = buff_FirstFromFlags(STAT(BUFFS, attacker)).m_id;
+
+                       if (!Obituary_WeaponDeath(targ, true, deathtype, targ.netname, attacker_name, deathlocation, CS(targ).killcount, kill_count_to_attacker))
+                               Obituary_SpecialDeath(targ, true, deathtype, targ.netname, attacker_name, deathlocation, CS(targ).killcount, kill_count_to_attacker, f3);
+               }
+       }
+
+       // =============
+       // ACCIDENT/TRAP
+       // =============
+       else
+       {
+               switch(DEATH_ENT(deathtype))
+               {
+                       // For now, we're just forcing HURTTRIGGER to behave as "DEATH_VOID" and giving it no special options...
+                       // Later on you will only be able to make custom messages using DEATH_CUSTOM,
+                       // and there will be a REAL DEATH_VOID implementation which mappers will use.
+                       case DEATH_HURTTRIGGER:
+                       {
+                               Obituary_SpecialDeath(targ, false, deathtype,
+                                       targ.netname,
+                                       inflictor.message,
+                                       deathlocation,
+                                       CS(targ).killcount,
+                                       0,
+                                       0);
+                               break;
+                       }
+
+                       case DEATH_CUSTOM:
+                       {
+                               Obituary_SpecialDeath(targ, false, deathtype,
+                                       targ.netname,
+                                       ((strstrofs(deathmessage, "%", 0) < 0) ? strcat("%s ", deathmessage) : deathmessage),
+                                       deathlocation,
+                                       CS(targ).killcount,
+                                       0,
+                                       0);
+                               break;
+                       }
+
+                       default:
+                       {
+                               Obituary_SpecialDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0, 0);
+                               break;
+                       }
+               }
+
+               LogDeath("accident", deathtype, targ, targ);
+               GiveFrags(targ, targ, -1, deathtype, weaponentity);
+
+               if(GameRules_scoring_add(targ, SCORE, 0) == -5)
+               {
+                       Send_Notification(NOTIF_ONE, targ, MSG_ANNCE, ANNCE_ACHIEVEMENT_BOTLIKE);
+                       if (!warmup_stage)
+                       {
+                               PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
+                       }
+               }
+       }
+
+       // reset target kill count
+       CS(targ).killcount = 0;
+}
+
+void Ice_Think(entity this)
+{
+       if(!STAT(FROZEN, this.owner) || this.owner.iceblock != this)
+       {
+               delete(this);
+               return;
+       }
+       vector ice_org = this.owner.origin - '0 0 16';
+       if (this.origin != ice_org)
+               setorigin(this, ice_org);
+       this.nextthink = time;
+}
+
+void Freeze(entity targ, float revivespeed, int frozen_type, bool show_waypoint)
+{
+       if(!IS_PLAYER(targ) && !IS_MONSTER(targ)) // TODO: only specified entities can be freezed
+               return;
+
+       if(STAT(FROZEN, targ))
+               return;
+
+       float targ_maxhealth = ((IS_MONSTER(targ)) ? targ.max_health : start_health);
+
+       STAT(FROZEN, targ) = frozen_type;
+       STAT(REVIVE_PROGRESS, targ) = ((frozen_type == FROZEN_TEMP_DYING) ? 1 : 0);
+       SetResource(targ, RES_HEALTH, ((frozen_type == FROZEN_TEMP_DYING) ? targ_maxhealth : 1));
+       targ.revive_speed = revivespeed;
+       if(targ.bot_attack)
+               IL_REMOVE(g_bot_targets, targ);
+       targ.bot_attack = false;
+       targ.freeze_time = time;
+
+       entity ice = new(ice);
+       ice.owner = targ;
+       ice.scale = targ.scale;
+       // set_movetype(ice, MOVETYPE_FOLLOW) would rotate the ice model with the player
+       setthink(ice, Ice_Think);
+       ice.nextthink = time;
+       ice.frame = floor(random() * 21); // ice model has 20 different looking frames
+       setmodel(ice, MDL_ICE);
+       ice.alpha = 1;
+       ice.colormod = Team_ColorRGB(targ.team);
+       ice.glowmod = ice.colormod;
+       targ.iceblock = ice;
+       targ.revival_time = 0;
+
+       Ice_Think(ice);
+
+       RemoveGrapplingHooks(targ);
+
+       FOREACH_CLIENT(IS_PLAYER(it),
+       {
+               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+           {
+               .entity weaponentity = weaponentities[slot];
+               if(it.(weaponentity).hook.aiment == targ)
+                       RemoveHook(it.(weaponentity).hook);
+           }
+       });
+
+       // add 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, bool reset_health)
+{
+       if(!STAT(FROZEN, targ))
+               return;
+
+       if (reset_health && STAT(FROZEN, targ) != FROZEN_TEMP_DYING)
+               SetResource(targ, RES_HEALTH, ((IS_PLAYER(targ)) ? start_health : targ.max_health));
+
+       targ.pauseregen_finished = time + autocvar_g_balance_pause_health_regen;
+
+       STAT(FROZEN, targ) = 0;
+       STAT(REVIVE_PROGRESS, targ) = 0;
+       targ.revival_time = time;
+       if(!targ.bot_attack)
+               IL_PUSH(g_bot_targets, targ);
+       targ.bot_attack = true;
+
+       WaypointSprite_Kill(targ.waypointsprite_attached);
+
+       FOREACH_CLIENT(IS_PLAYER(it),
+       {
+               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+           {
+               .entity weaponentity = weaponentities[slot];
+               if(it.(weaponentity).hook.aiment == targ)
+                       RemoveHook(it.(weaponentity).hook);
+           }
+       });
+
+       // remove the ice block
+       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)
+{
+       float complainteamdamage = 0;
+       float mirrordamage = 0;
+       float mirrorforce = 0;
+
+       if (game_stopped || (IS_CLIENT(targ) && CS(targ).killcount == FRAGS_SPECTATOR))
+               return;
+
+       entity attacker_save = attacker;
+
+       // special rule: gravity bombs and sound-based attacks do not affect team mates (other than for disconnecting the hook)
+       if(DEATH_ISWEAPON(deathtype, WEP_HOOK) || (deathtype & HITTYPE_SOUND))
+       {
+               if(IS_PLAYER(targ) && SAME_TEAM(targ, attacker))
+               {
+                       return;
+               }
+       }
+
+       if(deathtype == DEATH_KILL.m_id || deathtype == DEATH_TEAMCHANGE.m_id || deathtype == DEATH_AUTOTEAMCHANGE.m_id)
+       {
+               // exit the vehicle before killing (fixes a crash)
+               if(IS_PLAYER(targ) && targ.vehicle)
+                       vehicles_exit(targ.vehicle, VHEF_RELEASE);
+
+               // These are ALWAYS lethal
+               // No damage modification here
+               // Instead, prepare the victim for his death...
+               SetResourceExplicit(targ, RES_ARMOR, 0);
+               targ.spawnshieldtime = 0;
+               SetResourceExplicit(targ, RES_HEALTH, 0.9); // this is < 1
+               targ.flags -= targ.flags & FL_GODMODE;
+               damage = 100000;
+       }
+       else if(deathtype == DEATH_MIRRORDAMAGE.m_id || deathtype == DEATH_NOAMMO.m_id)
+       {
+               // no processing
+       }
+       else
+       {
+               // nullify damage if teamplay is on
+               if(deathtype != DEATH_TELEFRAG.m_id)
+               if(IS_PLAYER(attacker))
+               {
+                       if(IS_PLAYER(targ) && targ != attacker && (IS_INDEPENDENT_PLAYER(attacker) || IS_INDEPENDENT_PLAYER(targ)))
+                       {
+                               damage = 0;
+                               force = '0 0 0';
+                       }
+                       else if(SAME_TEAM(attacker, targ))
+                       {
+                               if(autocvar_teamplay_mode == 1)
+                                       damage = 0;
+                               else if(attacker != targ)
+                               {
+                                       if(autocvar_teamplay_mode == 2)
+                                       {
+                                               if(IS_PLAYER(targ) && !IS_DEAD(targ))
+                                               {
+                                                       attacker.dmg_team = attacker.dmg_team + damage;
+                                                       complainteamdamage = attacker.dmg_team - autocvar_g_teamdamage_threshold;
+                                               }
+                                       }
+                                       else if(autocvar_teamplay_mode == 3)
+                                               damage = 0;
+                                       else if(autocvar_teamplay_mode == 4)
+                                       {
+                                               if(IS_PLAYER(targ) && !IS_DEAD(targ))
+                                               {
+                                                       attacker.dmg_team = attacker.dmg_team + damage;
+                                                       complainteamdamage = attacker.dmg_team - autocvar_g_teamdamage_threshold;
+                                                       if(complainteamdamage > 0)
+                                                               mirrordamage = autocvar_g_mirrordamage * complainteamdamage;
+                                                       mirrorforce = autocvar_g_mirrordamage * vlen(force);
+                                                       damage = autocvar_g_friendlyfire * damage;
+                                                       // mirrordamage will be used LATER
+
+                                                       if(autocvar_g_mirrordamage_virtual)
+                                                       {
+                                                               vector v  = healtharmor_applydamage(GetResource(attacker, RES_ARMOR), autocvar_g_balance_armor_blockpercent, deathtype, mirrordamage);
+                                                               attacker.dmg_take += v.x;
+                                                               attacker.dmg_save += v.y;
+                                                               attacker.dmg_inflictor = inflictor;
+                                                               mirrordamage = v.z;
+                                                               mirrorforce = 0;
+                                                       }
+
+                                                       if(autocvar_g_friendlyfire_virtual)
+                                                       {
+                                                               vector v = healtharmor_applydamage(GetResource(targ, RES_ARMOR), autocvar_g_balance_armor_blockpercent, deathtype, damage);
+                                                               targ.dmg_take += v.x;
+                                                               targ.dmg_save += v.y;
+                                                               targ.dmg_inflictor = inflictor;
+                                                               damage = 0;
+                                                               if(!autocvar_g_friendlyfire_virtual_force)
+                                                                       force = '0 0 0';
+                                                       }
+                                               }
+                                               else if(!targ.canteamdamage)
+                                                       damage = 0;
+                                       }
+                               }
+                       }
+               }
+
+               if (!DEATH_ISSPECIAL(deathtype))
+               {
+                       damage *= g_weapondamagefactor;
+                       mirrordamage *= g_weapondamagefactor;
+                       complainteamdamage *= g_weapondamagefactor;
+                       force = force * g_weaponforcefactor;
+                       mirrorforce *= g_weaponforcefactor;
+               }
+
+               // should this be changed at all? If so, in what way?
+               MUTATOR_CALLHOOK(Damage_Calculate, inflictor, attacker, targ, deathtype, damage, mirrordamage, force, attacker.(weaponentity));
+               damage = M_ARGV(4, float);
+               mirrordamage = M_ARGV(5, float);
+               force = M_ARGV(6, vector);
+
+               if(IS_PLAYER(targ) && damage > 0 && attacker)
+               {
+                       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+                   {
+                       .entity went = weaponentities[slot];
+                       if(targ.(went).hook && targ.(went).hook.aiment == attacker)
+                               RemoveHook(targ.(went).hook);
+                   }
+               }
+
+               if(STAT(FROZEN, targ) && !ITEM_DAMAGE_NEEDKILL(deathtype)
+                       && deathtype != DEATH_TEAMCHANGE.m_id && deathtype != DEATH_AUTOTEAMCHANGE.m_id)
+               {
+                       if(autocvar_g_frozen_revive_falldamage > 0 && deathtype == DEATH_FALL.m_id && damage >= autocvar_g_frozen_revive_falldamage)
+                       {
+                               Unfreeze(targ, false);
+                               SetResource(targ, RES_HEALTH, autocvar_g_frozen_revive_falldamage_health);
+                               Send_Effect(EFFECT_ICEORGLASS, targ.origin, '0 0 0', 3);
+                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_REVIVED_FALL, targ.netname);
+                               Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_FREEZETAG_REVIVE_SELF);
+                       }
+
+                       damage = 0;
+                       force *= autocvar_g_frozen_force;
+               }
+
+               if(IS_PLAYER(targ) && STAT(FROZEN, targ)
+                       && ITEM_DAMAGE_NEEDKILL(deathtype) && !autocvar_g_frozen_damage_trigger)
+               {
+                       Send_Effect(EFFECT_TELEPORT, targ.origin, '0 0 0', 1);
+
+                       entity spot = SelectSpawnPoint(targ, false);
+                       if(spot)
+                       {
+                               damage = 0;
+                               targ.deadflag = DEAD_NO;
+
+                               targ.angles = spot.angles;
+
+                               targ.effects = 0;
+                               targ.effects |= EF_TELEPORT_BIT;
+
+                               targ.angles_z = 0; // never spawn tilted even if the spot says to
+                               targ.fixangle = true; // turn this way immediately
+                               targ.velocity = '0 0 0';
+                               targ.avelocity = '0 0 0';
+                               targ.punchangle = '0 0 0';
+                               targ.punchvector = '0 0 0';
+                               targ.oldvelocity = targ.velocity;
+
+                               targ.spawnorigin = spot.origin;
+                               setorigin(targ, spot.origin + '0 0 1' * (1 - targ.mins.z - 24));
+                               // don't reset back to last position, even if new position is stuck in solid
+                               targ.oldorigin = targ.origin;
+
+                               Send_Effect(EFFECT_TELEPORT, targ.origin, '0 0 0', 1);
+                       }
+               }
+
+               if(!MUTATOR_IS_ENABLED(mutator_instagib))
+               {
+                       // apply strength multiplier
+                       if (attacker.items & ITEM_Strength.m_itemid)
+                       {
+                               if(targ == attacker)
+                               {
+                                       damage = damage * autocvar_g_balance_powerup_strength_selfdamage;
+                                       force = force * autocvar_g_balance_powerup_strength_selfforce;
+                               }
+                               else
+                               {
+                                       damage = damage * autocvar_g_balance_powerup_strength_damage;
+                                       force = force * autocvar_g_balance_powerup_strength_force;
+                               }
+                       }
+
+                       // apply invincibility multiplier
+                       if (targ.items & ITEM_Shield.m_itemid)
+                       {
+                               damage = damage * autocvar_g_balance_powerup_invincible_takedamage;
+                               if (targ != attacker)
+                               {
+                                       force = force * autocvar_g_balance_powerup_invincible_takeforce;
+                               }
+                       }
+               }
+
+               if (targ == attacker)
+                       damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself
+
+               // count the damage
+               if(attacker)
+               if(!IS_DEAD(targ))
+               if(deathtype != DEATH_BUFF.m_id)
+               if(targ.takedamage == DAMAGE_AIM)
+               if(targ != attacker)
+               {
+                       entity victim;
+                       if(IS_VEHICLE(targ) && targ.owner)
+                               victim = targ.owner;
+                       else
+                               victim = targ;
+
+                       if(IS_PLAYER(victim) || (IS_TURRET(victim) && victim.active == ACTIVE_ACTIVE) || IS_MONSTER(victim) || MUTATOR_CALLHOOK(PlayHitsound, victim, attacker))
+                       {
+                               if(DIFF_TEAM(victim, attacker) && !STAT(FROZEN, victim))
+                               {
+                                       if(damage > 0)
+                                       {
+                                               if(deathtype != DEATH_FIRE.m_id)
+                                               {
+                                                       if(PHYS_INPUT_BUTTON_CHAT(victim))
+                                                               attacker.typehitsound += 1;
+                                                       else
+                                                               attacker.damage_dealt += damage;
+                                               }
+
+                                               damage_goodhits += 1;
+                                               damage_gooddamage += damage;
+
+                                               if (!DEATH_ISSPECIAL(deathtype))
+                                               {
+                                                       if(IS_PLAYER(targ)) // don't do this for vehicles
+                                                       if(IsFlying(victim))
+                                                               yoda = 1;
+                                               }
+                                       }
+                               }
+                               else if(IS_PLAYER(attacker))
+                               {
+                                       // if enemy gets frozen in this frame and receives other damage don't
+                                       // play the typehitsound e.g. when hit by multiple bullets of the shotgun
+                                       if (deathtype != DEATH_FIRE.m_id && (!STAT(FROZEN, victim) || time > victim.freeze_time))
+                                       {
+                                               attacker.typehitsound += 1;
+                                       }
+                                       if(complainteamdamage > 0)
+                                               if(time > CS(attacker).teamkill_complain)
+                                               {
+                                                       CS(attacker).teamkill_complain = time + 5;
+                                                       CS(attacker).teamkill_soundtime = time + 0.4;
+                                                       CS(attacker).teamkill_soundsource = targ;
+                                               }
+                               }
+                       }
+               }
+       }
+
+       // apply push
+       if (targ.damageforcescale)
+       if (force)
+       if (!IS_PLAYER(targ) || time >= targ.spawnshieldtime || targ == attacker)
+       {
+               vector farce = damage_explosion_calcpush(targ.damageforcescale * force, targ.velocity, autocvar_g_balance_damagepush_speedfactor);
+               if(targ.move_movetype == MOVETYPE_PHYSICS)
+               {
+                       entity farcent = new(farce);
+                       farcent.enemy = targ;
+                       farcent.movedir = farce * 10;
+                       if(targ.mass)
+                               farcent.movedir = farcent.movedir * targ.mass;
+                       farcent.origin = hitloc;
+                       farcent.forcetype = FORCETYPE_FORCEATPOS;
+                       farcent.nextthink = time + 0.1;
+                       setthink(farcent, SUB_Remove);
+               }
+               else if(targ.move_movetype != MOVETYPE_NOCLIP)
+               {
+                       targ.velocity = targ.velocity + farce;
+               }
+               UNSET_ONGROUND(targ);
+               UpdateCSQCProjectile(targ);
+       }
+       // apply damage
+       if (damage != 0 || (targ.damageforcescale && force))
+       if (targ.event_damage)
+               targ.event_damage (targ, inflictor, attacker, damage, deathtype, weaponentity, hitloc, force);
+
+       // apply mirror damage if any
+       if(!autocvar_g_mirrordamage_onlyweapons || DEATH_WEAPONOF(deathtype) != WEP_Null)
+       if(mirrordamage > 0 || mirrorforce > 0)
+       {
+               attacker = attacker_save;
+
+               force = normalize(attacker.origin + attacker.view_ofs - hitloc) * mirrorforce;
+               Damage(attacker, inflictor, attacker, mirrordamage, DEATH_MIRRORDAMAGE.m_id, weaponentity, attacker.origin, force);
+       }
+}
+
+float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe,
+                                                               float inflictorselfdamage, float forceintensity, float forcezscale, int deathtype, .entity weaponentity, entity directhitentity)
+       // Returns total damage applies to creatures
+{
+       entity  targ;
+       vector  force;
+       float   total_damage_to_creatures;
+       entity  next;
+       float   tfloordmg;
+       float   tfloorforce;
+
+       float stat_damagedone;
+
+       if(RadiusDamage_running)
+       {
+               backtrace("RadiusDamage called recursively! Expect stuff to go HORRIBLY wrong.");
+               return 0;
+       }
+
+       RadiusDamage_running = 1;
+
+       tfloordmg = autocvar_g_throughfloor_damage;
+       tfloorforce = autocvar_g_throughfloor_force;
+
+       total_damage_to_creatures = 0;
+
+       if(deathtype != (WEP_HOOK.m_id | HITTYPE_SECONDARY | HITTYPE_BOUNCE)) // only send gravity bomb damage once
+               if(!(deathtype & HITTYPE_SOUND)) // do not send radial sound damage (bandwidth hog)
+               {
+                       force = inflictorvelocity;
+                       if(force == '0 0 0')
+                               force = '0 0 -1';
+                       else
+                               force = normalize(force);
+                       if(forceintensity >= 0)
+                               Damage_DamageInfo(inflictororigin, coredamage, edgedamage, rad, forceintensity * force, deathtype, 0, attacker);
+                       else
+                               Damage_DamageInfo(inflictororigin, coredamage, edgedamage, -rad, (-forceintensity) * force, deathtype, 0, attacker);
+               }
+
+       stat_damagedone = 0;
+
+       targ = WarpZone_FindRadius (inflictororigin, rad + MAX_DAMAGEEXTRARADIUS, false);
+       while (targ)
+       {
+               next = targ.chain;
+               if ((targ != inflictor) || inflictorselfdamage)
+               if (((cantbe != targ) && !mustbe) || (mustbe == targ))
+               if (targ.takedamage)
+               {
+                       vector nearest;
+                       vector diff;
+                       float power;
+
+                       // LordHavoc: measure distance to nearest point on target (not origin)
+                       // (this guarentees 100% damage on a touch impact)
+                       nearest = targ.WarpZone_findradius_nearest;
+                       diff = targ.WarpZone_findradius_dist;
+                       // round up a little on the damage to ensure full damage on impacts
+                       // and turn the distance into a fraction of the radius
+                       power = 1 - ((vlen (diff) - bound(MIN_DAMAGEEXTRARADIUS, targ.damageextraradius, MAX_DAMAGEEXTRARADIUS)) / rad);
+                       //bprint(" ");
+                       //bprint(ftos(power));
+                       //if (targ == attacker)
+                       //      print(ftos(power), "\n");
+                       if (power > 0)
+                       {
+                               float finaldmg;
+                               if (power > 1)
+                                       power = 1;
+                               finaldmg = coredamage * power + edgedamage * (1 - power);
+                               if (finaldmg > 0)
+                               {
+                                       float a;
+                                       float c;
+                                       vector hitloc;
+                                       vector myblastorigin;
+                                       vector center;
+
+                                       myblastorigin = WarpZone_TransformOrigin(targ, inflictororigin);
+
+                                       // if it's a player, use the view origin as reference
+                                       center = CENTER_OR_VIEWOFS(targ);
+
+                                       force = normalize(center - myblastorigin);
+                                       force = force * (finaldmg / coredamage) * forceintensity;
+                                       hitloc = nearest;
+
+                                       // apply special scaling along the z axis if set
+                                       // NOTE: 0 value is not allowed for compatibility, in the case of weapon cvars not being set
+                                       if(forcezscale)
+                                               force.z *= forcezscale;
+
+                                       if(targ != directhitentity)
+                                       {
+                                               float hits;
+                                               float total;
+                                               float hitratio;
+                                               float mininv_f, mininv_d;
+
+                                               // test line of sight to multiple positions on box,
+                                               // and do damage if any of them hit
+                                               hits = 0;
+
+                                               // we know: max stddev of hitratio = 1 / (2 * sqrt(n))
+                                               // so for a given max stddev:
+                                               // n = (1 / (2 * max stddev of hitratio))^2
+
+                                               mininv_d = (finaldmg * (1-tfloordmg)) / autocvar_g_throughfloor_damage_max_stddev;
+                                               mininv_f = (vlen(force) * (1-tfloorforce)) / autocvar_g_throughfloor_force_max_stddev;
+
+                                               if(autocvar_g_throughfloor_debug)
+                                                       LOG_INFOF("THROUGHFLOOR: D=%f F=%f max(dD)=1/%f max(dF)=1/%f", finaldmg, vlen(force), mininv_d, mininv_f);
+
+
+                                               total = 0.25 * (max(mininv_f, mininv_d) ** 2);
+
+                                               if(autocvar_g_throughfloor_debug)
+                                                       LOG_INFOF(" steps=%f", total);
+
+
+                                               if (IS_PLAYER(targ))
+                                                       total = ceil(bound(autocvar_g_throughfloor_min_steps_player, total, autocvar_g_throughfloor_max_steps_player));
+                                               else
+                                                       total = ceil(bound(autocvar_g_throughfloor_min_steps_other, total, autocvar_g_throughfloor_max_steps_other));
+
+                                               if(autocvar_g_throughfloor_debug)
+                                                       LOG_INFOF(" steps=%f dD=%f dF=%f", total, finaldmg * (1-tfloordmg) / (2 * sqrt(total)), vlen(force) * (1-tfloorforce) / (2 * sqrt(total)));
+
+                                               for(c = 0; c < total; ++c)
+                                               {
+                                                       //traceline(targ.WarpZone_findradius_findorigin, nearest, MOVE_NOMONSTERS, inflictor);
+                                                       WarpZone_TraceLine(inflictororigin, WarpZone_UnTransformOrigin(targ, nearest), MOVE_NOMONSTERS, inflictor);
+                                                       if (trace_fraction == 1 || trace_ent == targ)
+                                                       {
+                                                               ++hits;
+                                                               if (hits > 1)
+                                                                       hitloc = hitloc + nearest;
+                                                               else
+                                                                       hitloc = nearest;
+                                                       }
+                                                       nearest.x = targ.origin.x + targ.mins.x + random() * targ.size.x;
+                                                       nearest.y = targ.origin.y + targ.mins.y + random() * targ.size.y;
+                                                       nearest.z = targ.origin.z + targ.mins.z + random() * targ.size.z;
+                                               }
+
+                                               nearest = hitloc * (1 / max(1, hits));
+                                               hitratio = (hits / total);
+                                               a = bound(0, tfloordmg + (1-tfloordmg) * hitratio, 1);
+                                               finaldmg = finaldmg * a;
+                                               a = bound(0, tfloorforce + (1-tfloorforce) * hitratio, 1);
+                                               force = force * a;
+
+                                               if(autocvar_g_throughfloor_debug)
+                                                       LOG_INFOF(" D=%f F=%f", finaldmg, vlen(force));
+                                       }
+
+                                       //if (targ == attacker)
+                                       //{
+                                       //      print("hits ", ftos(hits), " / ", ftos(total));
+                                       //      print(" finaldmg ", ftos(finaldmg), " force ", vtos(force));
+                                       //      print(" (", ftos(a), ")\n");
+                                       //}
+                                       if(finaldmg || force)
+                                       {
+                                               if(targ.iscreature)
+                                               {
+                                                       total_damage_to_creatures += finaldmg;
+
+                                                       if(accuracy_isgooddamage(attacker, targ))
+                                                               stat_damagedone += finaldmg;
+                                               }
+
+                                               if(targ == directhitentity || DEATH_ISSPECIAL(deathtype))
+                                                       Damage(targ, inflictor, attacker, finaldmg, deathtype, weaponentity, nearest, force);
+                                               else
+                                                       Damage(targ, inflictor, attacker, finaldmg, deathtype | HITTYPE_SPLASH, weaponentity, nearest, force);
+                                       }
+                               }
+                       }
+               }
+               targ = next;
+       }
+
+       RadiusDamage_running = 0;
+
+       if(!DEATH_ISSPECIAL(deathtype))
+               accuracy_add(attacker, DEATH_WEAPONOF(deathtype), 0, min(coredamage, stat_damagedone));
+
+       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)
+{
+       return RadiusDamageForSource(inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, 
+                                                                       cantbe, mustbe, false, forceintensity, 1, deathtype, weaponentity, directhitentity);
+}
+
+bool Heal(entity targ, entity inflictor, float amount, float limit)
+{
+       if(game_stopped || (IS_CLIENT(targ) && CS(targ).killcount == FRAGS_SPECTATOR) || STAT(FROZEN, targ) || IS_DEAD(targ))
+               return false;
+
+       bool healed = false;
+       if(targ.event_heal)
+               healed = targ.event_heal(targ, inflictor, amount, limit);
+       // TODO: additional handling? what if the healing kills them? should this abort if healing would do so etc
+       // TODO: healing fx!
+       // TODO: armor healing?
+       return healed;
+}
+
+float Fire_IsBurning(entity e)
+{
+       return (time < e.fire_endtime);
+}
+
+float Fire_AddDamage(entity e, entity o, float d, float t, float dt)
+{
+       float dps;
+       float maxtime, mintime, maxdamage, mindamage, maxdps, mindps, totaldamage, totaltime;
+
+       if(IS_PLAYER(e))
+       {
+               if(IS_DEAD(e))
+                       return -1;
+       }
+       else
+       {
+               if(!e.fire_burner)
+               {
+                       // print("adding a fire burner to ", e.classname, "\n");
+                       e.fire_burner = new(fireburner);
+                       setthink(e.fire_burner, fireburner_think);
+                       e.fire_burner.nextthink = time;
+                       e.fire_burner.owner = e;
+               }
+       }
+
+       t = max(t, 0.1);
+       dps = d / t;
+       if(Fire_IsBurning(e))
+       {
+               mintime = e.fire_endtime - time;
+               maxtime = max(mintime, t);
+
+               mindps = e.fire_damagepersec;
+               maxdps = max(mindps, dps);
+
+               if(maxtime > mintime || maxdps > mindps)
+               {
+                       // Constraints:
+
+                       // damage we have right now
+                       mindamage = mindps * mintime;
+
+                       // damage we want to get
+                       maxdamage = mindamage + d;
+
+                       // but we can't exceed maxtime * maxdps!
+                       totaldamage = min(maxdamage, maxtime * maxdps);
+
+                       // LEMMA:
+                       // Look at:
+                       // totaldamage = min(mindamage + d, maxtime * maxdps)
+                       // We see:
+                       // totaldamage <= maxtime * maxdps
+                       // ==> totaldamage / maxdps <= maxtime.
+                       // We also see:
+                       // totaldamage / mindps = min(mindamage / mindps + d, maxtime * maxdps / mindps)
+                       //                     >= min(mintime, maxtime)
+                       // ==> totaldamage / maxdps >= mintime.
+
+                       /*
+                       // how long do we damage then?
+                       // at least as long as before
+                       // but, never exceed maxdps
+                       totaltime = max(mintime, totaldamage / maxdps); // always <= maxtime due to lemma
+                       */
+
+                       // alternate:
+                       // at most as long as maximum allowed
+                       // but, never below mindps
+                       totaltime = min(maxtime, totaldamage / mindps); // always >= mintime due to lemma
+
+                       // assuming t > mintime, dps > mindps:
+                       // we get d = t * dps = maxtime * maxdps
+                       // totaldamage = min(maxdamage, maxtime * maxdps) = min(... + d, maxtime * maxdps) = maxtime * maxdps
+                       // totaldamage / maxdps = maxtime
+                       // totaldamage / mindps > totaldamage / maxdps = maxtime
+                       // FROM THIS:
+                       // a) totaltime = max(mintime, maxtime) = maxtime
+                       // b) totaltime = min(maxtime, totaldamage / maxdps) = maxtime
+
+                       // assuming t <= mintime:
+                       // we get maxtime = mintime
+                       // a) totaltime = max(mintime, ...) >= mintime, also totaltime <= maxtime by the lemma, therefore totaltime = mintime = maxtime
+                       // b) totaltime = min(maxtime, ...) <= maxtime, also totaltime >= mintime by the lemma, therefore totaltime = mintime = maxtime
+
+                       // assuming dps <= mindps:
+                       // we get mindps = maxdps.
+                       // With this, the lemma says that mintime <= totaldamage / mindps = totaldamage / maxdps <= maxtime.
+                       // a) totaltime = max(mintime, totaldamage / maxdps) = totaldamage / maxdps
+                       // b) totaltime = min(maxtime, totaldamage / mindps) = totaldamage / maxdps
+
+                       e.fire_damagepersec = totaldamage / totaltime;
+                       e.fire_endtime = time + totaltime;
+                       if(totaldamage > 1.2 * mindamage)
+                       {
+                               e.fire_deathtype = dt;
+                               if(e.fire_owner != o)
+                               {
+                                       e.fire_owner = o;
+                                       e.fire_hitsound = false;
+                               }
+                       }
+                       if(accuracy_isgooddamage(o, e))
+                               accuracy_add(o, DEATH_WEAPONOF(dt), 0, max(0, totaldamage - mindamage));
+                       return max(0, totaldamage - mindamage); // can never be negative, but to make sure
+               }
+               else
+                       return 0;
+       }
+       else
+       {
+               e.fire_damagepersec = dps;
+               e.fire_endtime = time + t;
+               e.fire_deathtype = dt;
+               e.fire_owner = o;
+               e.fire_hitsound = false;
+               if(accuracy_isgooddamage(o, e))
+                       accuracy_add(o, DEATH_WEAPONOF(dt), 0, d);
+               return d;
+       }
+}
+
+void Fire_ApplyDamage(entity e)
+{
+       float t, d, hi, ty;
+       entity o;
+
+       if (!Fire_IsBurning(e))
+               return;
+
+       for(t = 0, o = e.owner; o.owner && t < 16; o = o.owner, ++t);
+       if(IS_NOT_A_CLIENT(o))
+               o = e.fire_owner;
+
+       // water and slime stop fire
+       if(e.waterlevel)
+       if(e.watertype != CONTENT_LAVA)
+               e.fire_endtime = 0;
+
+       // ice stops fire
+       if(STAT(FROZEN, e))
+               e.fire_endtime = 0;
+
+       t = min(frametime, e.fire_endtime - time);
+       d = e.fire_damagepersec * t;
+
+       hi = e.fire_owner.damage_dealt;
+       ty = e.fire_owner.typehitsound;
+       Damage(e, e, e.fire_owner, d, e.fire_deathtype, DMG_NOWEP, e.origin, '0 0 0');
+       if(e.fire_hitsound && e.fire_owner)
+       {
+               e.fire_owner.damage_dealt = hi;
+               e.fire_owner.typehitsound = ty;
+       }
+       e.fire_hitsound = true;
+
+       if(!IS_INDEPENDENT_PLAYER(e) && !STAT(FROZEN, e))
+       {
+               IL_EACH(g_damagedbycontents, it.damagedbycontents && it != e,
+               {
+                       if(!IS_DEAD(it) && it.takedamage && !IS_INDEPENDENT_PLAYER(it))
+                       if(boxesoverlap(e.absmin, e.absmax, it.absmin, it.absmax))
+                       {
+                               t = autocvar_g_balance_firetransfer_time * (e.fire_endtime - time);
+                               d = autocvar_g_balance_firetransfer_damage * e.fire_damagepersec * t;
+                               Fire_AddDamage(it, o, d, t, DEATH_FIRE.m_id);
+                       }
+               });
+       }
+}
+
+void Fire_ApplyEffect(entity e)
+{
+       if(Fire_IsBurning(e))
+               e.effects |= EF_FLAME;
+       else
+               e.effects &= ~EF_FLAME;
+}
+
+void fireburner_think(entity this)
+{
+       // for players, this is done in the regular loop
+       if(wasfreed(this.owner))
+       {
+               delete(this);
+               return;
+       }
+       Fire_ApplyEffect(this.owner);
+       if(!Fire_IsBurning(this.owner))
+       {
+               this.owner.fire_burner = NULL;
+               delete(this);
+               return;
+       }
+       Fire_ApplyDamage(this.owner);
+       this.nextthink = time;
+}
diff --git a/qcsrc/server/damage.qh b/qcsrc/server/damage.qh
new file mode 100644 (file)
index 0000000..14dbaf0
--- /dev/null
@@ -0,0 +1,163 @@
+#pragma once
+
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+    #include <common/weapons/_all.qh>
+    #include <common/stats.qh>
+    #include <server/items/items.qh>
+    #include <server/miscfunctions.qh>
+    #include <lib/warpzone/common.qh>
+    #include <common/constants.qh>
+    #include <common/teams.qh>
+    #include <common/util.qh>
+    #include <common/weapons/_all.qh>
+    #include "weapons/accuracy.qh"
+    #include "weapons/csqcprojectile.qh"
+    #include "weapons/selection.qh"
+    #include "autocvars.qh"
+    #include "constants.qh"
+    #include <common/notifications/all.qh>
+    #include <common/deathtypes/all.qh>
+    #include <server/mutators/_mod.qh>
+    #include <common/turrets/sv_turrets.qh>
+    #include <common/vehicles/all.qh>
+    #include <lib/csqcmodel/sv_model.qh>
+    #include <common/playerstats.qh>
+    #include "hook.qh"
+    #include "scores.qh"
+    #include "spawnpoints.qh"
+#endif
+
+.void(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force) event_damage;
+
+.bool(entity targ, entity inflictor, float amount, float limit) event_heal;
+
+.float dmg;
+.float dmg_edge;
+.float dmg_force;
+.float dmg_radius;
+
+bool Damage_DamageInfo_SendEntity(entity this, entity to, int sf);
+
+void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, int deathtype, float bloodtype, entity dmgowner);
+
+float checkrules_firstblood;
+
+.float damagedbycontents;
+.float damagedbytriggers;
+
+float yoda;
+float damage_goodhits;
+float damage_gooddamage;
+
+.float pain_finished; // Added by Supajoe
+
+.float dmg_team;
+.float teamkill_complain;
+.float teamkill_soundtime;
+.entity teamkill_soundsource;
+.entity pusher;
+.bool istypefrag;
+.float taunt_soundtime;
+
+.float spawnshieldtime;
+
+.int totalfrags;
+
+.bool canteamdamage;
+
+.vector death_origin;
+
+.float damage_dealt, typehitsound, killsound;
+
+// used for custom deathtype
+string deathmessage;
+
+float IsFlying(entity a);
+
+void UpdateFrags(entity player, int f);
+
+// NOTE: f=0 means still count as a (positive) kill, but count no frags for it
+void W_SwitchWeapon_Force(Player this, Weapon w, .entity weaponentity);
+void GiveFrags (entity attacker, entity targ, float f, int deathtype, .entity weaponentity);
+
+string AppendItemcodes(string s, entity player);
+
+void LogDeath(string mode, int deathtype, entity killer, entity killed);
+
+void Obituary_SpecialDeath(
+       entity notif_target,
+       float murder,
+       int deathtype,
+       string s1, string s2, string s3,
+       float f1, float f2, float f3);
+
+float w_deathtype;
+float Obituary_WeaponDeath(
+       entity notif_target,
+       float murder,
+       int deathtype,
+       string s1, string s2, string s3,
+       float f1, float f2);
+
+void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .entity weaponentity);
+
+// Frozen status effect
+//const int FROZEN_NOT              = 0;
+const int FROZEN_NORMAL             = 1;
+const int FROZEN_TEMP_REVIVING      = 2;
+const int FROZEN_TEMP_DYING         = 3;
+
+.float revival_time; // time at which player was last revived
+.float revive_speed; // NOTE: multiplier (anything above 1 is instaheal)
+.float freeze_time;
+.entity iceblock;
+.entity frozen_by; // for ice fields
+
+void Ice_Think(entity this);
+
+void Freeze(entity targ, float revivespeed, int frozen_type, bool show_waypoint);
+
+void Unfreeze(entity targ, bool reset_health);
+
+// WEAPONTODO
+#define DMG_NOWEP (weaponentities[0])
+
+// NOTE: the .weaponentity parameter can be set to DMG_NOWEP if the attack wasn't caused by a weapon or player
+void Damage (entity targ, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force);
+
+float RadiusDamage_running;
+float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float inflictorselfdamage, float forceintensity, float forcezscale, int deathtype, .entity weaponentity, entity directhitentity);
+       // Returns total damage applies 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 damageforcescale;
+const float MIN_DAMAGEEXTRARADIUS = 2;
+const float MAX_DAMAGEEXTRARADIUS = 16;
+.float damageextraradius;
+
+// Calls .event_heal on the target so that they can handle healing themselves
+// a limit of RES_LIMIT_NONE should be handled by the entity as its max health (if applicable)
+bool Heal(entity targ, entity inflictor, float amount, float limit);
+
+.float fire_damagepersec;
+.float fire_endtime;
+.float fire_deathtype;
+.entity fire_owner;
+.float fire_hitsound;
+.entity fire_burner;
+
+void fireburner_think(entity this);
+
+float Fire_IsBurning(entity e);
+
+float Fire_AddDamage(entity e, entity o, float d, float t, float dt);
+
+void Fire_ApplyDamage(entity e);
+
+void Fire_ApplyEffect(entity e);
+
+IntrusiveList g_damagedbycontents;
+STATIC_INIT(g_damagedbycontents) { g_damagedbycontents = IL_NEW(); }
diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc
deleted file mode 100644 (file)
index f5d5f91..0000000
+++ /dev/null
@@ -1,1301 +0,0 @@
-#include "g_damage.qh"
-
-#include <common/effects/all.qh>
-#include "bot/api.qh"
-#include "g_hook.qh"
-#include <server/client.qh>
-#include <server/gamelog.qh>
-#include <server/items/items.qh>
-#include <server/mutators/_mod.qh>
-#include <server/sv_main.qh>
-#include "teamplay.qh"
-#include "scores.qh"
-#include "spawnpoints.qh"
-#include "../common/state.qh"
-#include "../common/physics/player.qh"
-#include "resources.qh"
-#include "../common/vehicles/all.qh"
-#include "../common/items/_mod.qh"
-#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
-#include "../common/mutators/mutator/instagib/sv_instagib.qh"
-#include "../common/mutators/mutator/buffs/buffs.qh"
-#include "weapons/accuracy.qh"
-#include "weapons/csqcprojectile.qh"
-#include "weapons/selection.qh"
-#include "../common/constants.qh"
-#include "../common/deathtypes/all.qh"
-#include <common/mapobjects/defs.qh>
-#include <common/mapobjects/triggers.qh>
-#include "../common/notifications/all.qh"
-#include "../common/physics/movetypes/movetypes.qh"
-#include "../common/playerstats.qh"
-#include "../common/teams.qh"
-#include "../common/util.qh"
-#include <common/gamemodes/_mod.qh>
-#include <common/gamemodes/rules.qh>
-#include <common/weapons/_all.qh>
-#include "../lib/csqcmodel/sv_model.qh"
-#include "../lib/warpzone/common.qh"
-
-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)
-{
-       // TODO route through PlayerScores instead
-       if(game_stopped) return;
-
-       if(f < 0)
-       {
-               if(targ == attacker)
-               {
-                       // suicide
-                       GameRules_scoring_add(attacker, SUICIDES, 1);
-               }
-               else
-               {
-                       // teamkill
-                       GameRules_scoring_add(attacker, TEAMKILLS, 1);
-               }
-       }
-       else
-       {
-               // regular frag
-               GameRules_scoring_add(attacker, KILLS, 1);
-               if(!warmup_stage && targ.playerid)
-                       PlayerStats_GameReport_Event_Player(attacker, sprintf("kills-%d", targ.playerid), 1);
-       }
-
-       GameRules_scoring_add(targ, DEATHS, 1);
-
-       // FIXME fix the mess this is (we have REAL points now!)
-       if(MUTATOR_CALLHOOK(GiveFragsForKill, attacker, targ, f, deathtype, attacker.(weaponentity)))
-               f = M_ARGV(2, float);
-
-       attacker.totalfrags += f;
-
-       if(f)
-               UpdateFrags(attacker, f);
-}
-
-string AppendItemcodes(string s, entity player)
-{
-       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-       {
-               .entity weaponentity = weaponentities[slot];
-               int w = player.(weaponentity).m_weapon.m_id;
-               if(w == 0)
-                       w = player.(weaponentity).cnt; // previous weapon
-               if(w != 0 || slot == 0)
-                       s = strcat(s, ftos(w));
-       }
-       if(time < STAT(STRENGTH_FINISHED, player))
-               s = strcat(s, "S");
-       if(time < STAT(INVINCIBLE_FINISHED, player))
-               s = strcat(s, "I");
-       if(PHYS_INPUT_BUTTON_CHAT(player))
-               s = strcat(s, "T");
-       // TODO: include these codes as a flag on the item itself
-       MUTATOR_CALLHOOK(LogDeath_AppendItemCodes, player, s);
-       s = M_ARGV(1, string);
-       return s;
-}
-
-void LogDeath(string mode, int deathtype, entity killer, entity killed)
-{
-       string s;
-       if(!autocvar_sv_eventlog)
-               return;
-       s = strcat(":kill:", mode);
-       s = strcat(s, ":", ftos(killer.playerid));
-       s = strcat(s, ":", ftos(killed.playerid));
-       s = strcat(s, ":type=", Deathtype_Name(deathtype));
-       s = strcat(s, ":items=");
-       s = AppendItemcodes(s, killer);
-       if(killed != killer)
-       {
-               s = strcat(s, ":victimitems=");
-               s = AppendItemcodes(s, killed);
-       }
-       GameLogEcho(s);
-}
-
-void Obituary_SpecialDeath(
-       entity notif_target,
-       float murder,
-       int deathtype,
-       string s1, string s2, string s3,
-       float f1, float f2, float f3)
-{
-       if(!DEATH_ISSPECIAL(deathtype))
-       {
-               backtrace("Obituary_SpecialDeath called without a special deathtype?\n");
-               return;
-       }
-
-       entity deathent = REGISTRY_GET(Deathtypes, deathtype - DT_FIRST);
-       if (!deathent)
-       {
-               backtrace("Obituary_SpecialDeath: Could not find deathtype entity!\n");
-               return;
-       }
-
-       if(g_cts && deathtype == DEATH_KILL.m_id)
-               return; // TODO: somehow put this in CTS gamemode file!
-
-       Notification death_message = (murder) ? deathent.death_msgmurder : deathent.death_msgself;
-       if(death_message)
-       {
-               Send_Notification_WOCOVA(
-                       NOTIF_ONE,
-                       notif_target,
-                       MSG_MULTI,
-                       death_message,
-                       s1, s2, s3, "",
-                       f1, f2, f3, 0
-               );
-               Send_Notification_WOCOVA(
-                       NOTIF_ALL_EXCEPT,
-                       notif_target,
-                       MSG_INFO,
-                       death_message.nent_msginfo,
-                       s1, s2, s3, "",
-                       f1, f2, f3, 0
-               );
-       }
-}
-
-float Obituary_WeaponDeath(
-       entity notif_target,
-       float murder,
-       int deathtype,
-       string s1, string s2, string s3,
-       float f1, float f2)
-{
-       Weapon death_weapon = DEATH_WEAPONOF(deathtype);
-       if (death_weapon == WEP_Null)
-               return false;
-
-       w_deathtype = deathtype;
-       Notification death_message = ((murder) ? death_weapon.wr_killmessage(death_weapon) : death_weapon.wr_suicidemessage(death_weapon));
-       w_deathtype = false;
-
-       if (death_message)
-       {
-               Send_Notification_WOCOVA(
-                       NOTIF_ONE,
-                       notif_target,
-                       MSG_MULTI,
-                       death_message,
-                       s1, s2, s3, "",
-                       f1, f2, 0, 0
-               );
-               // send the info part to everyone
-               Send_Notification_WOCOVA(
-                       NOTIF_ALL_EXCEPT,
-                       notif_target,
-                       MSG_INFO,
-                       death_message.nent_msginfo,
-                       s1, s2, s3, "",
-                       f1, f2, 0, 0
-               );
-       }
-       else
-       {
-               LOG_TRACEF(
-                       "Obituary_WeaponDeath(): ^1Deathtype ^7(%d)^1 has no notification for weapon %s!\n",
-                       deathtype,
-                       death_weapon.netname
-               );
-       }
-
-       return true;
-}
-
-bool frag_centermessage_override(entity attacker, entity targ, int deathtype, int kill_count_to_attacker, int kill_count_to_target, string attacker_name)
-{
-       if(deathtype == DEATH_FIRE.m_id)
-       {
-               Send_Notification(NOTIF_ONE, attacker, MSG_CHOICE, CHOICE_FRAG_FIRE, targ.netname, kill_count_to_attacker, (IS_BOT_CLIENT(targ) ? -1 : CS(targ).ping));
-               Send_Notification(NOTIF_ONE, targ, MSG_CHOICE, CHOICE_FRAGGED_FIRE, attacker_name, kill_count_to_target, GetResource(attacker, RES_HEALTH), GetResource(attacker, RES_ARMOR), (IS_BOT_CLIENT(attacker) ? -1 : CS(attacker).ping));
-               return true;
-       }
-
-       return MUTATOR_CALLHOOK(FragCenterMessage, attacker, targ, deathtype, kill_count_to_attacker, kill_count_to_target);
-}
-
-void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .entity weaponentity)
-{
-       // Sanity check
-       if (!IS_PLAYER(targ)) { backtrace("Obituary called on non-player?!\n"); return; }
-
-       // Declarations
-       float notif_firstblood = false;
-       float kill_count_to_attacker, kill_count_to_target;
-       bool notif_anonymous = false;
-       string attacker_name = attacker.netname;
-
-       // Set final information for the death
-       targ.death_origin = targ.origin;
-       string deathlocation = (autocvar_notification_server_allows_location ? NearestLocation(targ.death_origin) : "");
-
-       // Abort now if a mutator requests it
-       if (MUTATOR_CALLHOOK(ClientObituary, inflictor, attacker, targ, deathtype, attacker.(weaponentity))) { CS(targ).killcount = 0; return; }
-       notif_anonymous = M_ARGV(5, bool);
-
-       if(notif_anonymous)
-               attacker_name = "Anonymous player";
-
-       #ifdef NOTIFICATIONS_DEBUG
-       Debug_Notification(
-               sprintf(
-                       "Obituary(%s, %s, %s, %s = %d);\n",
-                       attacker_name,
-                       inflictor.netname,
-                       targ.netname,
-                       Deathtype_Name(deathtype),
-                       deathtype
-               )
-       );
-       #endif
-
-       // =======
-       // SUICIDE
-       // =======
-       if(targ == attacker)
-       {
-               if(DEATH_ISSPECIAL(deathtype))
-               {
-                       if(deathtype == DEATH_TEAMCHANGE.m_id || deathtype == DEATH_AUTOTEAMCHANGE.m_id)
-                       {
-                               Obituary_SpecialDeath(targ, false, deathtype, targ.netname, deathlocation, "", targ.team, 0, 0);
-                       }
-                       else
-                       {
-                               switch(DEATH_ENT(deathtype))
-                               {
-                                       case DEATH_MIRRORDAMAGE:
-                                       {
-                                               Obituary_SpecialDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0, 0);
-                                               break;
-                                       }
-
-                                       default:
-                                       {
-                                               Obituary_SpecialDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0, 0);
-                                               break;
-                                       }
-                               }
-                       }
-               }
-               else if (!Obituary_WeaponDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0))
-               {
-                       backtrace("SUICIDE: what the hell happened here?\n");
-                       return;
-               }
-               LogDeath("suicide", deathtype, targ, targ);
-               if(deathtype != DEATH_AUTOTEAMCHANGE.m_id) // special case: don't negate frags if auto switched
-                       GiveFrags(attacker, targ, -1, deathtype, weaponentity);
-       }
-
-       // ======
-       // MURDER
-       // ======
-       else if(IS_PLAYER(attacker))
-       {
-               if(SAME_TEAM(attacker, targ))
-               {
-                       LogDeath("tk", deathtype, attacker, targ);
-                       GiveFrags(attacker, targ, -1, deathtype, weaponentity);
-
-                       CS(attacker).killcount = 0;
-
-                       Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAG, targ.netname);
-                       Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAGGED, attacker_name);
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(targ.team, INFO_DEATH_TEAMKILL), targ.netname, attacker_name, deathlocation, CS(targ).killcount);
-
-                       // In this case, the death message will ALWAYS be "foo was betrayed by bar"
-                       // No need for specific death/weapon messages...
-               }
-               else
-               {
-                       LogDeath("frag", deathtype, attacker, targ);
-                       GiveFrags(attacker, targ, 1, deathtype, weaponentity);
-
-                       CS(attacker).taunt_soundtime = time + 1;
-                       CS(attacker).killcount = CS(attacker).killcount + 1;
-
-                       attacker.killsound += 1;
-
-                       // TODO: improve SPREE_ITEM and KILL_SPREE_LIST
-                       // these 2 macros are spread over multiple files
-                       #define SPREE_ITEM(counta,countb,center,normal,gentle) \
-                               case counta: \
-                                       Send_Notification(NOTIF_ONE, attacker, MSG_ANNCE, ANNCE_KILLSTREAK_##countb); \
-                                       if (!warmup_stage) \
-                                               PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
-                                       break;
-
-                       switch(CS(attacker).killcount)
-                       {
-                               KILL_SPREE_LIST
-                               default: break;
-                       }
-                       #undef SPREE_ITEM
-
-                       if(!warmup_stage && !checkrules_firstblood)
-                       {
-                               checkrules_firstblood = true;
-                               notif_firstblood = true; // modify the current messages so that they too show firstblood information
-                               PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
-                               PlayerStats_GameReport_Event_Player(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
-
-                               // tell spree_inf and spree_cen that this is a first-blood and first-victim event
-                               kill_count_to_attacker = -1;
-                               kill_count_to_target = -2;
-                       }
-                       else
-                       {
-                               kill_count_to_attacker = CS(attacker).killcount;
-                               kill_count_to_target = 0;
-                       }
-
-                       if(targ.istypefrag)
-                       {
-                               Send_Notification(
-                                       NOTIF_ONE,
-                                       attacker,
-                                       MSG_CHOICE,
-                                       CHOICE_TYPEFRAG,
-                                       targ.netname,
-                                       kill_count_to_attacker,
-                                       (IS_BOT_CLIENT(targ) ? -1 : CS(targ).ping)
-                               );
-                               Send_Notification(
-                                       NOTIF_ONE,
-                                       targ,
-                                       MSG_CHOICE,
-                                       CHOICE_TYPEFRAGGED,
-                                       attacker_name,
-                                       kill_count_to_target,
-                                       GetResource(attacker, RES_HEALTH),
-                                       GetResource(attacker, RES_ARMOR),
-                                       (IS_BOT_CLIENT(attacker) ? -1 : CS(attacker).ping)
-                               );
-                       }
-                       else if(!frag_centermessage_override(attacker, targ, deathtype, kill_count_to_attacker, kill_count_to_target, attacker_name))
-                       {
-                               Send_Notification(
-                                       NOTIF_ONE,
-                                       attacker,
-                                       MSG_CHOICE,
-                                       CHOICE_FRAG,
-                                       targ.netname,
-                                       kill_count_to_attacker,
-                                       (IS_BOT_CLIENT(targ) ? -1 : CS(targ).ping)
-                               );
-                               Send_Notification(
-                                       NOTIF_ONE,
-                                       targ,
-                                       MSG_CHOICE,
-                                       CHOICE_FRAGGED,
-                                       attacker_name,
-                                       kill_count_to_target,
-                                       GetResource(attacker, RES_HEALTH),
-                                       GetResource(attacker, RES_ARMOR),
-                                       (IS_BOT_CLIENT(attacker) ? -1 : CS(attacker).ping)
-                               );
-                       }
-
-                       int f3 = 0;
-                       if(deathtype == DEATH_BUFF.m_id)
-                               f3 = buff_FirstFromFlags(STAT(BUFFS, attacker)).m_id;
-
-                       if (!Obituary_WeaponDeath(targ, true, deathtype, targ.netname, attacker_name, deathlocation, CS(targ).killcount, kill_count_to_attacker))
-                               Obituary_SpecialDeath(targ, true, deathtype, targ.netname, attacker_name, deathlocation, CS(targ).killcount, kill_count_to_attacker, f3);
-               }
-       }
-
-       // =============
-       // ACCIDENT/TRAP
-       // =============
-       else
-       {
-               switch(DEATH_ENT(deathtype))
-               {
-                       // For now, we're just forcing HURTTRIGGER to behave as "DEATH_VOID" and giving it no special options...
-                       // Later on you will only be able to make custom messages using DEATH_CUSTOM,
-                       // and there will be a REAL DEATH_VOID implementation which mappers will use.
-                       case DEATH_HURTTRIGGER:
-                       {
-                               Obituary_SpecialDeath(targ, false, deathtype,
-                                       targ.netname,
-                                       inflictor.message,
-                                       deathlocation,
-                                       CS(targ).killcount,
-                                       0,
-                                       0);
-                               break;
-                       }
-
-                       case DEATH_CUSTOM:
-                       {
-                               Obituary_SpecialDeath(targ, false, deathtype,
-                                       targ.netname,
-                                       ((strstrofs(deathmessage, "%", 0) < 0) ? strcat("%s ", deathmessage) : deathmessage),
-                                       deathlocation,
-                                       CS(targ).killcount,
-                                       0,
-                                       0);
-                               break;
-                       }
-
-                       default:
-                       {
-                               Obituary_SpecialDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0, 0);
-                               break;
-                       }
-               }
-
-               LogDeath("accident", deathtype, targ, targ);
-               GiveFrags(targ, targ, -1, deathtype, weaponentity);
-
-               if(GameRules_scoring_add(targ, SCORE, 0) == -5)
-               {
-                       Send_Notification(NOTIF_ONE, targ, MSG_ANNCE, ANNCE_ACHIEVEMENT_BOTLIKE);
-                       if (!warmup_stage)
-                       {
-                               PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
-                       }
-               }
-       }
-
-       // reset target kill count
-       CS(targ).killcount = 0;
-}
-
-void Ice_Think(entity this)
-{
-       if(!STAT(FROZEN, this.owner) || this.owner.iceblock != this)
-       {
-               delete(this);
-               return;
-       }
-       vector ice_org = this.owner.origin - '0 0 16';
-       if (this.origin != ice_org)
-               setorigin(this, ice_org);
-       this.nextthink = time;
-}
-
-void Freeze(entity targ, float revivespeed, int frozen_type, bool show_waypoint)
-{
-       if(!IS_PLAYER(targ) && !IS_MONSTER(targ)) // TODO: only specified entities can be freezed
-               return;
-
-       if(STAT(FROZEN, targ))
-               return;
-
-       float targ_maxhealth = ((IS_MONSTER(targ)) ? targ.max_health : start_health);
-
-       STAT(FROZEN, targ) = frozen_type;
-       STAT(REVIVE_PROGRESS, targ) = ((frozen_type == FROZEN_TEMP_DYING) ? 1 : 0);
-       SetResource(targ, RES_HEALTH, ((frozen_type == FROZEN_TEMP_DYING) ? targ_maxhealth : 1));
-       targ.revive_speed = revivespeed;
-       if(targ.bot_attack)
-               IL_REMOVE(g_bot_targets, targ);
-       targ.bot_attack = false;
-       targ.freeze_time = time;
-
-       entity ice = new(ice);
-       ice.owner = targ;
-       ice.scale = targ.scale;
-       // set_movetype(ice, MOVETYPE_FOLLOW) would rotate the ice model with the player
-       setthink(ice, Ice_Think);
-       ice.nextthink = time;
-       ice.frame = floor(random() * 21); // ice model has 20 different looking frames
-       setmodel(ice, MDL_ICE);
-       ice.alpha = 1;
-       ice.colormod = Team_ColorRGB(targ.team);
-       ice.glowmod = ice.colormod;
-       targ.iceblock = ice;
-       targ.revival_time = 0;
-
-       Ice_Think(ice);
-
-       RemoveGrapplingHooks(targ);
-
-       FOREACH_CLIENT(IS_PLAYER(it),
-       {
-               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-           {
-               .entity weaponentity = weaponentities[slot];
-               if(it.(weaponentity).hook.aiment == targ)
-                       RemoveHook(it.(weaponentity).hook);
-           }
-       });
-
-       // add 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, bool reset_health)
-{
-       if(!STAT(FROZEN, targ))
-               return;
-
-       if (reset_health && STAT(FROZEN, targ) != FROZEN_TEMP_DYING)
-               SetResource(targ, RES_HEALTH, ((IS_PLAYER(targ)) ? start_health : targ.max_health));
-
-       targ.pauseregen_finished = time + autocvar_g_balance_pause_health_regen;
-
-       STAT(FROZEN, targ) = 0;
-       STAT(REVIVE_PROGRESS, targ) = 0;
-       targ.revival_time = time;
-       if(!targ.bot_attack)
-               IL_PUSH(g_bot_targets, targ);
-       targ.bot_attack = true;
-
-       WaypointSprite_Kill(targ.waypointsprite_attached);
-
-       FOREACH_CLIENT(IS_PLAYER(it),
-       {
-               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-           {
-               .entity weaponentity = weaponentities[slot];
-               if(it.(weaponentity).hook.aiment == targ)
-                       RemoveHook(it.(weaponentity).hook);
-           }
-       });
-
-       // remove the ice block
-       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)
-{
-       float complainteamdamage = 0;
-       float mirrordamage = 0;
-       float mirrorforce = 0;
-
-       if (game_stopped || (IS_CLIENT(targ) && CS(targ).killcount == FRAGS_SPECTATOR))
-               return;
-
-       entity attacker_save = attacker;
-
-       // special rule: gravity bombs and sound-based attacks do not affect team mates (other than for disconnecting the hook)
-       if(DEATH_ISWEAPON(deathtype, WEP_HOOK) || (deathtype & HITTYPE_SOUND))
-       {
-               if(IS_PLAYER(targ) && SAME_TEAM(targ, attacker))
-               {
-                       return;
-               }
-       }
-
-       if(deathtype == DEATH_KILL.m_id || deathtype == DEATH_TEAMCHANGE.m_id || deathtype == DEATH_AUTOTEAMCHANGE.m_id)
-       {
-               // exit the vehicle before killing (fixes a crash)
-               if(IS_PLAYER(targ) && targ.vehicle)
-                       vehicles_exit(targ.vehicle, VHEF_RELEASE);
-
-               // These are ALWAYS lethal
-               // No damage modification here
-               // Instead, prepare the victim for his death...
-               SetResourceExplicit(targ, RES_ARMOR, 0);
-               targ.spawnshieldtime = 0;
-               SetResourceExplicit(targ, RES_HEALTH, 0.9); // this is < 1
-               targ.flags -= targ.flags & FL_GODMODE;
-               damage = 100000;
-       }
-       else if(deathtype == DEATH_MIRRORDAMAGE.m_id || deathtype == DEATH_NOAMMO.m_id)
-       {
-               // no processing
-       }
-       else
-       {
-               // nullify damage if teamplay is on
-               if(deathtype != DEATH_TELEFRAG.m_id)
-               if(IS_PLAYER(attacker))
-               {
-                       if(IS_PLAYER(targ) && targ != attacker && (IS_INDEPENDENT_PLAYER(attacker) || IS_INDEPENDENT_PLAYER(targ)))
-                       {
-                               damage = 0;
-                               force = '0 0 0';
-                       }
-                       else if(SAME_TEAM(attacker, targ))
-                       {
-                               if(autocvar_teamplay_mode == 1)
-                                       damage = 0;
-                               else if(attacker != targ)
-                               {
-                                       if(autocvar_teamplay_mode == 2)
-                                       {
-                                               if(IS_PLAYER(targ) && !IS_DEAD(targ))
-                                               {
-                                                       attacker.dmg_team = attacker.dmg_team + damage;
-                                                       complainteamdamage = attacker.dmg_team - autocvar_g_teamdamage_threshold;
-                                               }
-                                       }
-                                       else if(autocvar_teamplay_mode == 3)
-                                               damage = 0;
-                                       else if(autocvar_teamplay_mode == 4)
-                                       {
-                                               if(IS_PLAYER(targ) && !IS_DEAD(targ))
-                                               {
-                                                       attacker.dmg_team = attacker.dmg_team + damage;
-                                                       complainteamdamage = attacker.dmg_team - autocvar_g_teamdamage_threshold;
-                                                       if(complainteamdamage > 0)
-                                                               mirrordamage = autocvar_g_mirrordamage * complainteamdamage;
-                                                       mirrorforce = autocvar_g_mirrordamage * vlen(force);
-                                                       damage = autocvar_g_friendlyfire * damage;
-                                                       // mirrordamage will be used LATER
-
-                                                       if(autocvar_g_mirrordamage_virtual)
-                                                       {
-                                                               vector v  = healtharmor_applydamage(GetResource(attacker, RES_ARMOR), autocvar_g_balance_armor_blockpercent, deathtype, mirrordamage);
-                                                               attacker.dmg_take += v.x;
-                                                               attacker.dmg_save += v.y;
-                                                               attacker.dmg_inflictor = inflictor;
-                                                               mirrordamage = v.z;
-                                                               mirrorforce = 0;
-                                                       }
-
-                                                       if(autocvar_g_friendlyfire_virtual)
-                                                       {
-                                                               vector v = healtharmor_applydamage(GetResource(targ, RES_ARMOR), autocvar_g_balance_armor_blockpercent, deathtype, damage);
-                                                               targ.dmg_take += v.x;
-                                                               targ.dmg_save += v.y;
-                                                               targ.dmg_inflictor = inflictor;
-                                                               damage = 0;
-                                                               if(!autocvar_g_friendlyfire_virtual_force)
-                                                                       force = '0 0 0';
-                                                       }
-                                               }
-                                               else if(!targ.canteamdamage)
-                                                       damage = 0;
-                                       }
-                               }
-                       }
-               }
-
-               if (!DEATH_ISSPECIAL(deathtype))
-               {
-                       damage *= g_weapondamagefactor;
-                       mirrordamage *= g_weapondamagefactor;
-                       complainteamdamage *= g_weapondamagefactor;
-                       force = force * g_weaponforcefactor;
-                       mirrorforce *= g_weaponforcefactor;
-               }
-
-               // should this be changed at all? If so, in what way?
-               MUTATOR_CALLHOOK(Damage_Calculate, inflictor, attacker, targ, deathtype, damage, mirrordamage, force, attacker.(weaponentity));
-               damage = M_ARGV(4, float);
-               mirrordamage = M_ARGV(5, float);
-               force = M_ARGV(6, vector);
-
-               if(IS_PLAYER(targ) && damage > 0 && attacker)
-               {
-                       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-                   {
-                       .entity went = weaponentities[slot];
-                       if(targ.(went).hook && targ.(went).hook.aiment == attacker)
-                               RemoveHook(targ.(went).hook);
-                   }
-               }
-
-               if(STAT(FROZEN, targ) && !ITEM_DAMAGE_NEEDKILL(deathtype)
-                       && deathtype != DEATH_TEAMCHANGE.m_id && deathtype != DEATH_AUTOTEAMCHANGE.m_id)
-               {
-                       if(autocvar_g_frozen_revive_falldamage > 0 && deathtype == DEATH_FALL.m_id && damage >= autocvar_g_frozen_revive_falldamage)
-                       {
-                               Unfreeze(targ, false);
-                               SetResource(targ, RES_HEALTH, autocvar_g_frozen_revive_falldamage_health);
-                               Send_Effect(EFFECT_ICEORGLASS, targ.origin, '0 0 0', 3);
-                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_REVIVED_FALL, targ.netname);
-                               Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_FREEZETAG_REVIVE_SELF);
-                       }
-
-                       damage = 0;
-                       force *= autocvar_g_frozen_force;
-               }
-
-               if(IS_PLAYER(targ) && STAT(FROZEN, targ)
-                       && ITEM_DAMAGE_NEEDKILL(deathtype) && !autocvar_g_frozen_damage_trigger)
-               {
-                       Send_Effect(EFFECT_TELEPORT, targ.origin, '0 0 0', 1);
-
-                       entity spot = SelectSpawnPoint(targ, false);
-                       if(spot)
-                       {
-                               damage = 0;
-                               targ.deadflag = DEAD_NO;
-
-                               targ.angles = spot.angles;
-
-                               targ.effects = 0;
-                               targ.effects |= EF_TELEPORT_BIT;
-
-                               targ.angles_z = 0; // never spawn tilted even if the spot says to
-                               targ.fixangle = true; // turn this way immediately
-                               targ.velocity = '0 0 0';
-                               targ.avelocity = '0 0 0';
-                               targ.punchangle = '0 0 0';
-                               targ.punchvector = '0 0 0';
-                               targ.oldvelocity = targ.velocity;
-
-                               targ.spawnorigin = spot.origin;
-                               setorigin(targ, spot.origin + '0 0 1' * (1 - targ.mins.z - 24));
-                               // don't reset back to last position, even if new position is stuck in solid
-                               targ.oldorigin = targ.origin;
-
-                               Send_Effect(EFFECT_TELEPORT, targ.origin, '0 0 0', 1);
-                       }
-               }
-
-               if(!MUTATOR_IS_ENABLED(mutator_instagib))
-               {
-                       // apply strength multiplier
-                       if (attacker.items & ITEM_Strength.m_itemid)
-                       {
-                               if(targ == attacker)
-                               {
-                                       damage = damage * autocvar_g_balance_powerup_strength_selfdamage;
-                                       force = force * autocvar_g_balance_powerup_strength_selfforce;
-                               }
-                               else
-                               {
-                                       damage = damage * autocvar_g_balance_powerup_strength_damage;
-                                       force = force * autocvar_g_balance_powerup_strength_force;
-                               }
-                       }
-
-                       // apply invincibility multiplier
-                       if (targ.items & ITEM_Shield.m_itemid)
-                       {
-                               damage = damage * autocvar_g_balance_powerup_invincible_takedamage;
-                               if (targ != attacker)
-                               {
-                                       force = force * autocvar_g_balance_powerup_invincible_takeforce;
-                               }
-                       }
-               }
-
-               if (targ == attacker)
-                       damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself
-
-               // count the damage
-               if(attacker)
-               if(!IS_DEAD(targ))
-               if(deathtype != DEATH_BUFF.m_id)
-               if(targ.takedamage == DAMAGE_AIM)
-               if(targ != attacker)
-               {
-                       entity victim;
-                       if(IS_VEHICLE(targ) && targ.owner)
-                               victim = targ.owner;
-                       else
-                               victim = targ;
-
-                       if(IS_PLAYER(victim) || (IS_TURRET(victim) && victim.active == ACTIVE_ACTIVE) || IS_MONSTER(victim) || MUTATOR_CALLHOOK(PlayHitsound, victim, attacker))
-                       {
-                               if(DIFF_TEAM(victim, attacker) && !STAT(FROZEN, victim))
-                               {
-                                       if(damage > 0)
-                                       {
-                                               if(deathtype != DEATH_FIRE.m_id)
-                                               {
-                                                       if(PHYS_INPUT_BUTTON_CHAT(victim))
-                                                               attacker.typehitsound += 1;
-                                                       else
-                                                               attacker.damage_dealt += damage;
-                                               }
-
-                                               damage_goodhits += 1;
-                                               damage_gooddamage += damage;
-
-                                               if (!DEATH_ISSPECIAL(deathtype))
-                                               {
-                                                       if(IS_PLAYER(targ)) // don't do this for vehicles
-                                                       if(IsFlying(victim))
-                                                               yoda = 1;
-                                               }
-                                       }
-                               }
-                               else if(IS_PLAYER(attacker))
-                               {
-                                       // if enemy gets frozen in this frame and receives other damage don't
-                                       // play the typehitsound e.g. when hit by multiple bullets of the shotgun
-                                       if (deathtype != DEATH_FIRE.m_id && (!STAT(FROZEN, victim) || time > victim.freeze_time))
-                                       {
-                                               attacker.typehitsound += 1;
-                                       }
-                                       if(complainteamdamage > 0)
-                                               if(time > CS(attacker).teamkill_complain)
-                                               {
-                                                       CS(attacker).teamkill_complain = time + 5;
-                                                       CS(attacker).teamkill_soundtime = time + 0.4;
-                                                       CS(attacker).teamkill_soundsource = targ;
-                                               }
-                               }
-                       }
-               }
-       }
-
-       // apply push
-       if (targ.damageforcescale)
-       if (force)
-       if (!IS_PLAYER(targ) || time >= targ.spawnshieldtime || targ == attacker)
-       {
-               vector farce = damage_explosion_calcpush(targ.damageforcescale * force, targ.velocity, autocvar_g_balance_damagepush_speedfactor);
-               if(targ.move_movetype == MOVETYPE_PHYSICS)
-               {
-                       entity farcent = new(farce);
-                       farcent.enemy = targ;
-                       farcent.movedir = farce * 10;
-                       if(targ.mass)
-                               farcent.movedir = farcent.movedir * targ.mass;
-                       farcent.origin = hitloc;
-                       farcent.forcetype = FORCETYPE_FORCEATPOS;
-                       farcent.nextthink = time + 0.1;
-                       setthink(farcent, SUB_Remove);
-               }
-               else if(targ.move_movetype != MOVETYPE_NOCLIP)
-               {
-                       targ.velocity = targ.velocity + farce;
-               }
-               UNSET_ONGROUND(targ);
-               UpdateCSQCProjectile(targ);
-       }
-       // apply damage
-       if (damage != 0 || (targ.damageforcescale && force))
-       if (targ.event_damage)
-               targ.event_damage (targ, inflictor, attacker, damage, deathtype, weaponentity, hitloc, force);
-
-       // apply mirror damage if any
-       if(!autocvar_g_mirrordamage_onlyweapons || DEATH_WEAPONOF(deathtype) != WEP_Null)
-       if(mirrordamage > 0 || mirrorforce > 0)
-       {
-               attacker = attacker_save;
-
-               force = normalize(attacker.origin + attacker.view_ofs - hitloc) * mirrorforce;
-               Damage(attacker, inflictor, attacker, mirrordamage, DEATH_MIRRORDAMAGE.m_id, weaponentity, attacker.origin, force);
-       }
-}
-
-float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe,
-                                                               float inflictorselfdamage, float forceintensity, float forcezscale, int deathtype, .entity weaponentity, entity directhitentity)
-       // Returns total damage applies to creatures
-{
-       entity  targ;
-       vector  force;
-       float   total_damage_to_creatures;
-       entity  next;
-       float   tfloordmg;
-       float   tfloorforce;
-
-       float stat_damagedone;
-
-       if(RadiusDamage_running)
-       {
-               backtrace("RadiusDamage called recursively! Expect stuff to go HORRIBLY wrong.");
-               return 0;
-       }
-
-       RadiusDamage_running = 1;
-
-       tfloordmg = autocvar_g_throughfloor_damage;
-       tfloorforce = autocvar_g_throughfloor_force;
-
-       total_damage_to_creatures = 0;
-
-       if(deathtype != (WEP_HOOK.m_id | HITTYPE_SECONDARY | HITTYPE_BOUNCE)) // only send gravity bomb damage once
-               if(!(deathtype & HITTYPE_SOUND)) // do not send radial sound damage (bandwidth hog)
-               {
-                       force = inflictorvelocity;
-                       if(force == '0 0 0')
-                               force = '0 0 -1';
-                       else
-                               force = normalize(force);
-                       if(forceintensity >= 0)
-                               Damage_DamageInfo(inflictororigin, coredamage, edgedamage, rad, forceintensity * force, deathtype, 0, attacker);
-                       else
-                               Damage_DamageInfo(inflictororigin, coredamage, edgedamage, -rad, (-forceintensity) * force, deathtype, 0, attacker);
-               }
-
-       stat_damagedone = 0;
-
-       targ = WarpZone_FindRadius (inflictororigin, rad + MAX_DAMAGEEXTRARADIUS, false);
-       while (targ)
-       {
-               next = targ.chain;
-               if ((targ != inflictor) || inflictorselfdamage)
-               if (((cantbe != targ) && !mustbe) || (mustbe == targ))
-               if (targ.takedamage)
-               {
-                       vector nearest;
-                       vector diff;
-                       float power;
-
-                       // LordHavoc: measure distance to nearest point on target (not origin)
-                       // (this guarentees 100% damage on a touch impact)
-                       nearest = targ.WarpZone_findradius_nearest;
-                       diff = targ.WarpZone_findradius_dist;
-                       // round up a little on the damage to ensure full damage on impacts
-                       // and turn the distance into a fraction of the radius
-                       power = 1 - ((vlen (diff) - bound(MIN_DAMAGEEXTRARADIUS, targ.damageextraradius, MAX_DAMAGEEXTRARADIUS)) / rad);
-                       //bprint(" ");
-                       //bprint(ftos(power));
-                       //if (targ == attacker)
-                       //      print(ftos(power), "\n");
-                       if (power > 0)
-                       {
-                               float finaldmg;
-                               if (power > 1)
-                                       power = 1;
-                               finaldmg = coredamage * power + edgedamage * (1 - power);
-                               if (finaldmg > 0)
-                               {
-                                       float a;
-                                       float c;
-                                       vector hitloc;
-                                       vector myblastorigin;
-                                       vector center;
-
-                                       myblastorigin = WarpZone_TransformOrigin(targ, inflictororigin);
-
-                                       // if it's a player, use the view origin as reference
-                                       center = CENTER_OR_VIEWOFS(targ);
-
-                                       force = normalize(center - myblastorigin);
-                                       force = force * (finaldmg / coredamage) * forceintensity;
-                                       hitloc = nearest;
-
-                                       // apply special scaling along the z axis if set
-                                       // NOTE: 0 value is not allowed for compatibility, in the case of weapon cvars not being set
-                                       if(forcezscale)
-                                               force.z *= forcezscale;
-
-                                       if(targ != directhitentity)
-                                       {
-                                               float hits;
-                                               float total;
-                                               float hitratio;
-                                               float mininv_f, mininv_d;
-
-                                               // test line of sight to multiple positions on box,
-                                               // and do damage if any of them hit
-                                               hits = 0;
-
-                                               // we know: max stddev of hitratio = 1 / (2 * sqrt(n))
-                                               // so for a given max stddev:
-                                               // n = (1 / (2 * max stddev of hitratio))^2
-
-                                               mininv_d = (finaldmg * (1-tfloordmg)) / autocvar_g_throughfloor_damage_max_stddev;
-                                               mininv_f = (vlen(force) * (1-tfloorforce)) / autocvar_g_throughfloor_force_max_stddev;
-
-                                               if(autocvar_g_throughfloor_debug)
-                                                       LOG_INFOF("THROUGHFLOOR: D=%f F=%f max(dD)=1/%f max(dF)=1/%f", finaldmg, vlen(force), mininv_d, mininv_f);
-
-
-                                               total = 0.25 * (max(mininv_f, mininv_d) ** 2);
-
-                                               if(autocvar_g_throughfloor_debug)
-                                                       LOG_INFOF(" steps=%f", total);
-
-
-                                               if (IS_PLAYER(targ))
-                                                       total = ceil(bound(autocvar_g_throughfloor_min_steps_player, total, autocvar_g_throughfloor_max_steps_player));
-                                               else
-                                                       total = ceil(bound(autocvar_g_throughfloor_min_steps_other, total, autocvar_g_throughfloor_max_steps_other));
-
-                                               if(autocvar_g_throughfloor_debug)
-                                                       LOG_INFOF(" steps=%f dD=%f dF=%f", total, finaldmg * (1-tfloordmg) / (2 * sqrt(total)), vlen(force) * (1-tfloorforce) / (2 * sqrt(total)));
-
-                                               for(c = 0; c < total; ++c)
-                                               {
-                                                       //traceline(targ.WarpZone_findradius_findorigin, nearest, MOVE_NOMONSTERS, inflictor);
-                                                       WarpZone_TraceLine(inflictororigin, WarpZone_UnTransformOrigin(targ, nearest), MOVE_NOMONSTERS, inflictor);
-                                                       if (trace_fraction == 1 || trace_ent == targ)
-                                                       {
-                                                               ++hits;
-                                                               if (hits > 1)
-                                                                       hitloc = hitloc + nearest;
-                                                               else
-                                                                       hitloc = nearest;
-                                                       }
-                                                       nearest.x = targ.origin.x + targ.mins.x + random() * targ.size.x;
-                                                       nearest.y = targ.origin.y + targ.mins.y + random() * targ.size.y;
-                                                       nearest.z = targ.origin.z + targ.mins.z + random() * targ.size.z;
-                                               }
-
-                                               nearest = hitloc * (1 / max(1, hits));
-                                               hitratio = (hits / total);
-                                               a = bound(0, tfloordmg + (1-tfloordmg) * hitratio, 1);
-                                               finaldmg = finaldmg * a;
-                                               a = bound(0, tfloorforce + (1-tfloorforce) * hitratio, 1);
-                                               force = force * a;
-
-                                               if(autocvar_g_throughfloor_debug)
-                                                       LOG_INFOF(" D=%f F=%f", finaldmg, vlen(force));
-                                       }
-
-                                       //if (targ == attacker)
-                                       //{
-                                       //      print("hits ", ftos(hits), " / ", ftos(total));
-                                       //      print(" finaldmg ", ftos(finaldmg), " force ", vtos(force));
-                                       //      print(" (", ftos(a), ")\n");
-                                       //}
-                                       if(finaldmg || force)
-                                       {
-                                               if(targ.iscreature)
-                                               {
-                                                       total_damage_to_creatures += finaldmg;
-
-                                                       if(accuracy_isgooddamage(attacker, targ))
-                                                               stat_damagedone += finaldmg;
-                                               }
-
-                                               if(targ == directhitentity || DEATH_ISSPECIAL(deathtype))
-                                                       Damage(targ, inflictor, attacker, finaldmg, deathtype, weaponentity, nearest, force);
-                                               else
-                                                       Damage(targ, inflictor, attacker, finaldmg, deathtype | HITTYPE_SPLASH, weaponentity, nearest, force);
-                                       }
-                               }
-                       }
-               }
-               targ = next;
-       }
-
-       RadiusDamage_running = 0;
-
-       if(!DEATH_ISSPECIAL(deathtype))
-               accuracy_add(attacker, DEATH_WEAPONOF(deathtype), 0, min(coredamage, stat_damagedone));
-
-       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)
-{
-       return RadiusDamageForSource(inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, 
-                                                                       cantbe, mustbe, false, forceintensity, 1, deathtype, weaponentity, directhitentity);
-}
-
-bool Heal(entity targ, entity inflictor, float amount, float limit)
-{
-       if(game_stopped || (IS_CLIENT(targ) && CS(targ).killcount == FRAGS_SPECTATOR) || STAT(FROZEN, targ) || IS_DEAD(targ))
-               return false;
-
-       bool healed = false;
-       if(targ.event_heal)
-               healed = targ.event_heal(targ, inflictor, amount, limit);
-       // TODO: additional handling? what if the healing kills them? should this abort if healing would do so etc
-       // TODO: healing fx!
-       // TODO: armor healing?
-       return healed;
-}
-
-float Fire_IsBurning(entity e)
-{
-       return (time < e.fire_endtime);
-}
-
-float Fire_AddDamage(entity e, entity o, float d, float t, float dt)
-{
-       float dps;
-       float maxtime, mintime, maxdamage, mindamage, maxdps, mindps, totaldamage, totaltime;
-
-       if(IS_PLAYER(e))
-       {
-               if(IS_DEAD(e))
-                       return -1;
-       }
-       else
-       {
-               if(!e.fire_burner)
-               {
-                       // print("adding a fire burner to ", e.classname, "\n");
-                       e.fire_burner = new(fireburner);
-                       setthink(e.fire_burner, fireburner_think);
-                       e.fire_burner.nextthink = time;
-                       e.fire_burner.owner = e;
-               }
-       }
-
-       t = max(t, 0.1);
-       dps = d / t;
-       if(Fire_IsBurning(e))
-       {
-               mintime = e.fire_endtime - time;
-               maxtime = max(mintime, t);
-
-               mindps = e.fire_damagepersec;
-               maxdps = max(mindps, dps);
-
-               if(maxtime > mintime || maxdps > mindps)
-               {
-                       // Constraints:
-
-                       // damage we have right now
-                       mindamage = mindps * mintime;
-
-                       // damage we want to get
-                       maxdamage = mindamage + d;
-
-                       // but we can't exceed maxtime * maxdps!
-                       totaldamage = min(maxdamage, maxtime * maxdps);
-
-                       // LEMMA:
-                       // Look at:
-                       // totaldamage = min(mindamage + d, maxtime * maxdps)
-                       // We see:
-                       // totaldamage <= maxtime * maxdps
-                       // ==> totaldamage / maxdps <= maxtime.
-                       // We also see:
-                       // totaldamage / mindps = min(mindamage / mindps + d, maxtime * maxdps / mindps)
-                       //                     >= min(mintime, maxtime)
-                       // ==> totaldamage / maxdps >= mintime.
-
-                       /*
-                       // how long do we damage then?
-                       // at least as long as before
-                       // but, never exceed maxdps
-                       totaltime = max(mintime, totaldamage / maxdps); // always <= maxtime due to lemma
-                       */
-
-                       // alternate:
-                       // at most as long as maximum allowed
-                       // but, never below mindps
-                       totaltime = min(maxtime, totaldamage / mindps); // always >= mintime due to lemma
-
-                       // assuming t > mintime, dps > mindps:
-                       // we get d = t * dps = maxtime * maxdps
-                       // totaldamage = min(maxdamage, maxtime * maxdps) = min(... + d, maxtime * maxdps) = maxtime * maxdps
-                       // totaldamage / maxdps = maxtime
-                       // totaldamage / mindps > totaldamage / maxdps = maxtime
-                       // FROM THIS:
-                       // a) totaltime = max(mintime, maxtime) = maxtime
-                       // b) totaltime = min(maxtime, totaldamage / maxdps) = maxtime
-
-                       // assuming t <= mintime:
-                       // we get maxtime = mintime
-                       // a) totaltime = max(mintime, ...) >= mintime, also totaltime <= maxtime by the lemma, therefore totaltime = mintime = maxtime
-                       // b) totaltime = min(maxtime, ...) <= maxtime, also totaltime >= mintime by the lemma, therefore totaltime = mintime = maxtime
-
-                       // assuming dps <= mindps:
-                       // we get mindps = maxdps.
-                       // With this, the lemma says that mintime <= totaldamage / mindps = totaldamage / maxdps <= maxtime.
-                       // a) totaltime = max(mintime, totaldamage / maxdps) = totaldamage / maxdps
-                       // b) totaltime = min(maxtime, totaldamage / mindps) = totaldamage / maxdps
-
-                       e.fire_damagepersec = totaldamage / totaltime;
-                       e.fire_endtime = time + totaltime;
-                       if(totaldamage > 1.2 * mindamage)
-                       {
-                               e.fire_deathtype = dt;
-                               if(e.fire_owner != o)
-                               {
-                                       e.fire_owner = o;
-                                       e.fire_hitsound = false;
-                               }
-                       }
-                       if(accuracy_isgooddamage(o, e))
-                               accuracy_add(o, DEATH_WEAPONOF(dt), 0, max(0, totaldamage - mindamage));
-                       return max(0, totaldamage - mindamage); // can never be negative, but to make sure
-               }
-               else
-                       return 0;
-       }
-       else
-       {
-               e.fire_damagepersec = dps;
-               e.fire_endtime = time + t;
-               e.fire_deathtype = dt;
-               e.fire_owner = o;
-               e.fire_hitsound = false;
-               if(accuracy_isgooddamage(o, e))
-                       accuracy_add(o, DEATH_WEAPONOF(dt), 0, d);
-               return d;
-       }
-}
-
-void Fire_ApplyDamage(entity e)
-{
-       float t, d, hi, ty;
-       entity o;
-
-       if (!Fire_IsBurning(e))
-               return;
-
-       for(t = 0, o = e.owner; o.owner && t < 16; o = o.owner, ++t);
-       if(IS_NOT_A_CLIENT(o))
-               o = e.fire_owner;
-
-       // water and slime stop fire
-       if(e.waterlevel)
-       if(e.watertype != CONTENT_LAVA)
-               e.fire_endtime = 0;
-
-       // ice stops fire
-       if(STAT(FROZEN, e))
-               e.fire_endtime = 0;
-
-       t = min(frametime, e.fire_endtime - time);
-       d = e.fire_damagepersec * t;
-
-       hi = e.fire_owner.damage_dealt;
-       ty = e.fire_owner.typehitsound;
-       Damage(e, e, e.fire_owner, d, e.fire_deathtype, DMG_NOWEP, e.origin, '0 0 0');
-       if(e.fire_hitsound && e.fire_owner)
-       {
-               e.fire_owner.damage_dealt = hi;
-               e.fire_owner.typehitsound = ty;
-       }
-       e.fire_hitsound = true;
-
-       if(!IS_INDEPENDENT_PLAYER(e) && !STAT(FROZEN, e))
-       {
-               IL_EACH(g_damagedbycontents, it.damagedbycontents && it != e,
-               {
-                       if(!IS_DEAD(it) && it.takedamage && !IS_INDEPENDENT_PLAYER(it))
-                       if(boxesoverlap(e.absmin, e.absmax, it.absmin, it.absmax))
-                       {
-                               t = autocvar_g_balance_firetransfer_time * (e.fire_endtime - time);
-                               d = autocvar_g_balance_firetransfer_damage * e.fire_damagepersec * t;
-                               Fire_AddDamage(it, o, d, t, DEATH_FIRE.m_id);
-                       }
-               });
-       }
-}
-
-void Fire_ApplyEffect(entity e)
-{
-       if(Fire_IsBurning(e))
-               e.effects |= EF_FLAME;
-       else
-               e.effects &= ~EF_FLAME;
-}
-
-void fireburner_think(entity this)
-{
-       // for players, this is done in the regular loop
-       if(wasfreed(this.owner))
-       {
-               delete(this);
-               return;
-       }
-       Fire_ApplyEffect(this.owner);
-       if(!Fire_IsBurning(this.owner))
-       {
-               this.owner.fire_burner = NULL;
-               delete(this);
-               return;
-       }
-       Fire_ApplyDamage(this.owner);
-       this.nextthink = time;
-}
diff --git a/qcsrc/server/g_damage.qh b/qcsrc/server/g_damage.qh
deleted file mode 100644 (file)
index 2348c7a..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-#pragma once
-
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-    #include <common/weapons/_all.qh>
-    #include <common/stats.qh>
-    #include <server/items/items.qh>
-    #include <server/miscfunctions.qh>
-    #include <lib/warpzone/common.qh>
-    #include <common/constants.qh>
-    #include <common/teams.qh>
-    #include <common/util.qh>
-    #include <common/weapons/_all.qh>
-    #include "weapons/accuracy.qh"
-    #include "weapons/csqcprojectile.qh"
-    #include "weapons/selection.qh"
-    #include "autocvars.qh"
-    #include "constants.qh"
-    #include <common/notifications/all.qh>
-    #include <common/deathtypes/all.qh>
-    #include <server/mutators/_mod.qh>
-    #include <common/turrets/sv_turrets.qh>
-    #include <common/vehicles/all.qh>
-    #include <lib/csqcmodel/sv_model.qh>
-    #include <common/playerstats.qh>
-    #include "g_hook.qh"
-    #include "scores.qh"
-    #include "spawnpoints.qh"
-#endif
-
-.void(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force) event_damage;
-
-.bool(entity targ, entity inflictor, float amount, float limit) event_heal;
-
-.float dmg;
-.float dmg_edge;
-.float dmg_force;
-.float dmg_radius;
-
-bool Damage_DamageInfo_SendEntity(entity this, entity to, int sf);
-
-void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, int deathtype, float bloodtype, entity dmgowner);
-
-float checkrules_firstblood;
-
-.float damagedbycontents;
-.float damagedbytriggers;
-
-float yoda;
-float damage_goodhits;
-float damage_gooddamage;
-
-.float pain_finished; // Added by Supajoe
-
-.float dmg_team;
-.float teamkill_complain;
-.float teamkill_soundtime;
-.entity teamkill_soundsource;
-.entity pusher;
-.bool istypefrag;
-.float taunt_soundtime;
-
-.float spawnshieldtime;
-
-.int totalfrags;
-
-.bool canteamdamage;
-
-.vector death_origin;
-
-.float damage_dealt, typehitsound, killsound;
-
-// used for custom deathtype
-string deathmessage;
-
-float IsFlying(entity a);
-
-void UpdateFrags(entity player, int f);
-
-// NOTE: f=0 means still count as a (positive) kill, but count no frags for it
-void W_SwitchWeapon_Force(Player this, Weapon w, .entity weaponentity);
-void GiveFrags (entity attacker, entity targ, float f, int deathtype, .entity weaponentity);
-
-string AppendItemcodes(string s, entity player);
-
-void LogDeath(string mode, int deathtype, entity killer, entity killed);
-
-void Obituary_SpecialDeath(
-       entity notif_target,
-       float murder,
-       int deathtype,
-       string s1, string s2, string s3,
-       float f1, float f2, float f3);
-
-float w_deathtype;
-float Obituary_WeaponDeath(
-       entity notif_target,
-       float murder,
-       int deathtype,
-       string s1, string s2, string s3,
-       float f1, float f2);
-
-void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .entity weaponentity);
-
-// Frozen status effect
-//const int FROZEN_NOT              = 0;
-const int FROZEN_NORMAL             = 1;
-const int FROZEN_TEMP_REVIVING      = 2;
-const int FROZEN_TEMP_DYING         = 3;
-
-.float revival_time; // time at which player was last revived
-.float revive_speed; // NOTE: multiplier (anything above 1 is instaheal)
-.float freeze_time;
-.entity iceblock;
-.entity frozen_by; // for ice fields
-
-void Ice_Think(entity this);
-
-void Freeze(entity targ, float revivespeed, int frozen_type, bool show_waypoint);
-
-void Unfreeze(entity targ, bool reset_health);
-
-// WEAPONTODO
-#define DMG_NOWEP (weaponentities[0])
-
-// NOTE: the .weaponentity parameter can be set to DMG_NOWEP if the attack wasn't caused by a weapon or player
-void Damage (entity targ, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force);
-
-float RadiusDamage_running;
-float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float inflictorselfdamage, float forceintensity, float forcezscale, int deathtype, .entity weaponentity, entity directhitentity);
-       // Returns total damage applies 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 damageforcescale;
-const float MIN_DAMAGEEXTRARADIUS = 2;
-const float MAX_DAMAGEEXTRARADIUS = 16;
-.float damageextraradius;
-
-// Calls .event_heal on the target so that they can handle healing themselves
-// a limit of RES_LIMIT_NONE should be handled by the entity as its max health (if applicable)
-bool Heal(entity targ, entity inflictor, float amount, float limit);
-
-.float fire_damagepersec;
-.float fire_endtime;
-.float fire_deathtype;
-.entity fire_owner;
-.float fire_hitsound;
-.entity fire_burner;
-
-void fireburner_think(entity this);
-
-float Fire_IsBurning(entity e);
-
-float Fire_AddDamage(entity e, entity o, float d, float t, float dt);
-
-void Fire_ApplyDamage(entity e);
-
-void Fire_ApplyEffect(entity e);
-
-IntrusiveList g_damagedbycontents;
-STATIC_INIT(g_damagedbycontents) { g_damagedbycontents = IL_NEW(); }
diff --git a/qcsrc/server/g_hook.qc b/qcsrc/server/g_hook.qc
deleted file mode 100644 (file)
index 5794720..0000000
+++ /dev/null
@@ -1,435 +0,0 @@
-#include "g_hook.qh"
-
-#include <server/bot/api.qh>
-#include <common/weapons/_all.qh>
-#include <common/stats.qh>
-#include <server/g_damage.qh>
-#include <server/miscfunctions.qh>
-#include <common/effects/all.qh>
-#include "weapons/common.qh"
-#include "weapons/csqcprojectile.qh"
-#include "weapons/weaponsystem.qh"
-#include "weapons/selection.qh"
-#include "weapons/tracing.qh"
-#include "player.qh"
-#include "command/common.qh"
-#include "command/vote.qh"
-#include "round_handler.qh"
-#include "../common/state.qh"
-#include "../common/physics/player.qh"
-#include "../common/vehicles/all.qh"
-#include "../common/constants.qh"
-#include "../common/util.qh"
-#include <common/net_linked.qh>
-#include <common/weapons/_all.qh>
-#include "../lib/warpzone/common.qh"
-#include "../lib/warpzone/server.qh"
-
-/*============================================
-
-      Wazat's Xonotic Grappling Hook
-
-        Contact: Wazat1@gmail.com
-
-
-Installation instructions:
---------------------------
-
-1. Place hook.c in your gamec source directory with the other source files.
-
-2. Add this line to the bottom of progs.src:
-
-gamec/hook.c
-
-3. Open defs.h and add these lines to the very bottom:
-
-// Wazat's grappling hook
-.entity                hook;
-void GrapplingHookFrame();
-void RemoveGrapplingHook(entity pl);
-void SetGrappleHookBindings();
-// hook impulses
-const float GRAPHOOK_FIRE              = 20;
-const float GRAPHOOK_RELEASE           = 21;
-// (note: you can change the hook impulse #'s to whatever you please)
-
-4. Open client.c and add this to the top of PutClientInServer():
-
-       RemoveGrapplingHook(this); // Wazat's Grappling Hook
-
-5. Find ClientConnect() (in client.c) and add these lines to the bottom:
-
-       // Wazat's grappling hook
-       SetGrappleHookBindings();
-
-6. Still in client.c, find PlayerPreThink and add this line just above the call to W_WeaponFrame:
-
-       GrapplingHookFrame();
-
-7. Build and test the mod.  You'll want to bind a key to "+hook" like this:
-bind ctrl "+hook"
-
-And you should be done!
-
-
-============================================*/
-
-void RemoveGrapplingHooks(entity pl)
-{
-       if(pl.move_movetype == MOVETYPE_FLY)
-               set_movetype(pl, MOVETYPE_WALK);
-
-       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-    {
-       .entity weaponentity = weaponentities[slot];
-       if(!pl.(weaponentity))
-               continue; // continue incase other slots exist?
-       if(pl.(weaponentity).hook)
-               delete(pl.(weaponentity).hook);
-       pl.(weaponentity).hook = NULL;
-    }
-
-       //pl.disableclientprediction = false;
-}
-
-void RemoveHook(entity this)
-{
-       entity player = this.realowner;
-    .entity weaponentity = this.weaponentity_fld;
-
-    if(player.(weaponentity).hook == this)
-       player.(weaponentity).hook = NULL;
-
-    if(player.move_movetype == MOVETYPE_FLY)
-       set_movetype(player, MOVETYPE_WALK);
-    delete(this);
-}
-
-void GrapplingHookReset(entity this)
-{
-       RemoveHook(this);
-}
-
-void GrapplingHook_Stop(entity this)
-{
-       Send_Effect(EFFECT_HOOK_IMPACT, this.origin, '0 0 0', 1);
-       sound (this, CH_SHOTS, SND_HOOK_IMPACT, VOL_BASE, ATTEN_NORM);
-
-       this.state = 1;
-       setthink(this, GrapplingHookThink);
-       this.nextthink = time;
-       settouch(this, func_null);
-       this.velocity = '0 0 0';
-       set_movetype(this, MOVETYPE_NONE);
-       this.hook_length = -1;
-}
-
-.vector hook_start, hook_end;
-bool GrapplingHookSend(entity this, entity to, int sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_HOOK);
-       sf = sf & 0x7F;
-       if(sound_allowed(MSG_BROADCAST, this.realowner))
-               sf |= 0x80;
-       WriteByte(MSG_ENTITY, sf);
-       if(sf & 1)
-       {
-               WriteByte(MSG_ENTITY, etof(this.realowner));
-               WriteByte(MSG_ENTITY, weaponslot(this.weaponentity_fld));
-       }
-       if(sf & 2)
-       {
-               WriteVector(MSG_ENTITY, this.hook_start);
-       }
-       if(sf & 4)
-       {
-               WriteVector(MSG_ENTITY, this.hook_end);
-       }
-       return true;
-}
-
-int autocvar_g_grappling_hook_tarzan;
-
-void GrapplingHookThink(entity this)
-{
-       float spd, dist, minlength, pullspeed, ropestretch, ropeairfriction, rubberforce, newlength, rubberforce_overstretch;
-       vector dir, org, end, v0, dv, v, myorg, vs;
-       .entity weaponentity = this.weaponentity_fld;
-       if(this.realowner.(weaponentity).hook != this)  // how did that happen?
-       {
-               error("Owner lost the hook!\n");
-               return;
-       }
-       if(LostMovetypeFollow(this) || game_stopped || (round_handler_IsActive() && !round_handler_IsRoundStarted()) || ((this.aiment.flags & FL_PROJECTILE) && this.aiment.classname != "nade"))
-       {
-               RemoveHook(this);
-               return;
-       }
-       if(this.aiment)
-               WarpZone_RefSys_AddIncrementally(this, this.aiment);
-
-       this.nextthink = time;
-
-       int s = W_GunAlign(this.realowner.(weaponentity), STAT(GUNALIGN, this.realowner)) - 1;
-       vs = hook_shotorigin[s];
-
-       makevectors(this.realowner.v_angle);
-       org = this.realowner.origin + this.realowner.view_ofs + v_forward * vs.x + v_right * -vs.y + v_up * vs.z;
-       myorg = WarpZone_RefSys_TransformOrigin(this.realowner, this, org);
-
-       if(this.hook_length < 0)
-               this.hook_length = vlen(myorg - this.origin);
-
-       int tarzan = autocvar_g_grappling_hook_tarzan;
-       entity pull_entity = this.realowner;
-       float velocity_multiplier = 1;
-       MUTATOR_CALLHOOK(GrappleHookThink, this, tarzan, pull_entity, velocity_multiplier);
-       tarzan = M_ARGV(1, int);
-       pull_entity = M_ARGV(2, entity);
-       velocity_multiplier = M_ARGV(3, float);
-
-       if(this.state == 1)
-       {
-               pullspeed = autocvar_g_balance_grapplehook_speed_pull;//2000;
-               // speed the rope is pulled with
-
-               rubberforce = autocvar_g_balance_grapplehook_force_rubber;//2000;
-               // force the rope will use if it is stretched
-
-               rubberforce_overstretch = autocvar_g_balance_grapplehook_force_rubber_overstretch;//1000;
-               // force the rope will use if it is stretched
-
-               minlength = autocvar_g_balance_grapplehook_length_min;//100;
-               // minimal rope length
-               // if the rope goes below this length, it isn't pulled any more
-
-               ropestretch = autocvar_g_balance_grapplehook_stretch;//400;
-               // if the rope is stretched by more than this amount, more rope is
-               // given to you again
-
-               ropeairfriction = autocvar_g_balance_grapplehook_airfriction;//0.2
-               // while hanging on the rope, this friction component will help you a
-               // bit to control the rope
-
-               bool frozen_pulling = (autocvar_g_grappling_hook_tarzan >= 2 && autocvar_g_balance_grapplehook_pull_frozen);
-
-               dir = this.origin - myorg;
-               dist = vlen(dir);
-               dir = normalize(dir);
-
-               if(tarzan)
-               {
-                       v = v0 = WarpZone_RefSys_TransformVelocity(pull_entity, this, pull_entity.velocity);
-
-                       // first pull the rope...
-                       if(this.realowner.(weaponentity).hook_state & HOOK_PULLING)
-                       {
-                               newlength = this.hook_length;
-                               newlength = max(newlength - pullspeed * frametime, minlength);
-
-                               if(newlength < dist - ropestretch) // overstretched?
-                               {
-                                       newlength = dist - ropestretch;
-                                       if(v * dir < 0) // only if not already moving in hook direction
-                                               v = v + frametime * dir * rubberforce_overstretch;
-                               }
-
-                               this.hook_length = newlength;
-                       }
-
-                       if(pull_entity.move_movetype == MOVETYPE_FLY)
-                               set_movetype(pull_entity, MOVETYPE_WALK);
-
-                       if(this.realowner.(weaponentity).hook_state & HOOK_RELEASING)
-                       {
-                               newlength = dist;
-                               this.hook_length = newlength;
-                       }
-                       else
-                       {
-                               // then pull the player
-                               spd = bound(0, (dist - this.hook_length) / ropestretch, 1);
-                               v = v * (1 - frametime * ropeairfriction);
-                               v = v + frametime * dir * spd * rubberforce;
-
-                               dv = ((v - v0) * dir) * dir;
-                               if(tarzan >= 2)
-                               {
-                                       if(this.aiment.move_movetype == MOVETYPE_WALK || this.aiment.classname == "nade")
-                                       {
-                                               entity aim_ent = ((IS_VEHICLE(this.aiment) && this.aiment.owner) ? this.aiment.owner : this.aiment);
-                                               v = v - dv * 0.5;
-                                               if((frozen_pulling && STAT(FROZEN, this.aiment)) || !frozen_pulling)
-                                               {
-                                                       this.aiment.velocity = this.aiment.velocity - dv * 0.5;
-                                                       UNSET_ONGROUND(this.aiment);
-                                                       if(this.aiment.flags & FL_PROJECTILE)
-                                                               UpdateCSQCProjectile(this.aiment);
-                                               }
-                                               if(this.aiment.classname == "nade")
-                                                       this.aiment.nextthink = time + autocvar_g_balance_grapplehook_nade_time; // set time after letting go?
-                                               aim_ent.pusher = this.realowner;
-                                               aim_ent.pushltime = time + autocvar_g_maxpushtime;
-                                               aim_ent.istypefrag = PHYS_INPUT_BUTTON_CHAT(aim_ent);
-                                       }
-                               }
-
-                               UNSET_ONGROUND(pull_entity);
-                       }
-
-                       if(!frozen_pulling && !(this.aiment.flags & FL_PROJECTILE))
-                               pull_entity.velocity = WarpZone_RefSys_TransformVelocity(this, pull_entity, v * velocity_multiplier);
-
-                       if(frozen_pulling && autocvar_g_balance_grapplehook_pull_frozen == 2 && !STAT(FROZEN, this.aiment))
-                       {
-                               RemoveHook(this);
-                               return;
-                       }
-               }
-               else
-               {
-                       end = this.origin - dir*50;
-                       dist = vlen(end - myorg);
-                       if(dist < 200)
-                               spd = dist * (pullspeed / 200);
-                       else
-                               spd = pullspeed;
-                       if(spd < 50)
-                               spd = 0;
-                       this.realowner.velocity = dir*spd;
-                       set_movetype(this.realowner, MOVETYPE_FLY);
-
-                       UNSET_ONGROUND(this.realowner);
-               }
-       }
-
-       makevectors(this.angles.x * '-1 0 0' + this.angles.y * '0 1 0');
-       myorg = WarpZone_RefSys_TransformOrigin(this, this.realowner, this.origin); // + v_forward * (-9);
-
-       if(myorg != this.hook_start)
-       {
-               this.SendFlags |= 2;
-               this.hook_start = myorg;
-       }
-       if(org != this.hook_end)
-       {
-               this.SendFlags |= 4;
-               this.hook_end = org;
-       }
-}
-
-void GrapplingHookTouch(entity this, entity toucher)
-{
-       if(toucher.move_movetype == MOVETYPE_FOLLOW)
-               return;
-       PROJECTILE_TOUCH(this, toucher);
-
-       GrapplingHook_Stop(this);
-
-       if(toucher)
-               //if(toucher.move_movetype != MOVETYPE_NONE)
-               {
-                       SetMovetypeFollow(this, toucher);
-                       WarpZone_RefSys_BeginAddingIncrementally(this, this.aiment);
-               }
-
-       //this.realowner.disableclientprediction = true;
-}
-
-void GrapplingHook_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
-{
-       if(GetResource(this, RES_HEALTH) <= 0)
-               return;
-
-       if (!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) // no exceptions
-               return; // g_balance_projectiledamage says to halt
-
-       TakeResource(this, RES_HEALTH, damage);
-
-       if (GetResource(this, RES_HEALTH) <= 0)
-       {
-               if(attacker != this.realowner)
-               {
-                       this.realowner.pusher = attacker;
-                       this.realowner.pushltime = time + autocvar_g_maxpushtime;
-                       this.realowner.istypefrag = PHYS_INPUT_BUTTON_CHAT(this.realowner);
-               }
-               RemoveHook(this);
-       }
-}
-
-void FireGrapplingHook(entity actor, .entity weaponentity)
-{
-       if(weaponLocked(actor)) return;
-       if(actor.vehicle) return;
-
-       int s = W_GunAlign(actor.(weaponentity), STAT(GUNALIGN, actor)) - 1;
-       vector vs = hook_shotorigin[s];
-       vector oldmovedir = actor.(weaponentity).movedir;
-       actor.(weaponentity).movedir = vs;
-       W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', true, 0, SND_HOOK_FIRE, CH_WEAPON_B, 0, WEP_HOOK.m_id);
-       W_MuzzleFlash(WEP_HOOK, actor, weaponentity, w_shotorg, '0 0 0');
-       actor.(weaponentity).movedir = oldmovedir;
-
-       entity missile = WarpZone_RefSys_SpawnSameRefSys(actor);
-       missile.owner = missile.realowner = actor;
-       actor.(weaponentity).hook = missile;
-       missile.weaponentity_fld = weaponentity;
-       missile.reset = GrapplingHookReset;
-       missile.classname = "grapplinghook";
-       missile.flags = FL_PROJECTILE;
-       IL_PUSH(g_projectiles, missile);
-       IL_PUSH(g_bot_dodge, missile);
-
-       set_movetype(missile, ((autocvar_g_balance_grapplehook_gravity) ? MOVETYPE_TOSS : MOVETYPE_FLY));
-       PROJECTILE_MAKETRIGGER(missile);
-
-       //setmodel (missile, MDL_HOOK); // precision set below
-       setsize (missile, '-3 -3 -3', '3 3 3');
-       setorigin(missile, w_shotorg);
-
-       missile.state = 0; // not latched onto anything
-
-       W_SetupProjVelocity_Explicit(missile, w_shotdir, v_up, autocvar_g_balance_grapplehook_speed_fly, 0, 0, 0, false);
-
-       missile.angles = vectoangles (missile.velocity);
-       //missile.glow_color = 250; // 244, 250
-       //missile.glow_size = 120;
-       settouch(missile, GrapplingHookTouch);
-       setthink(missile, GrapplingHookThink);
-       missile.nextthink = time;
-
-       missile.effects = /*EF_FULLBRIGHT | EF_ADDITIVE |*/ EF_LOWPRECISION;
-
-       SetResourceExplicit(missile, RES_HEALTH, autocvar_g_balance_grapplehook_health);
-       missile.event_damage = GrapplingHook_Damage;
-       missile.takedamage = DAMAGE_AIM;
-       missile.damageforcescale = 0;
-       missile.damagedbycontents = (autocvar_g_balance_grapplehook_damagedbycontents);
-       if(missile.damagedbycontents)
-               IL_PUSH(g_damagedbycontents, missile);
-
-       missile.hook_start = missile.hook_end = missile.origin;
-
-       Net_LinkEntity(missile, false, 0, GrapplingHookSend);
-}
-
-void GrappleHookInit()
-{
-       if(g_grappling_hook)
-       {
-               hook_shotorigin[0] = '8 8 -12';
-               hook_shotorigin[1] = '8 8 -12';
-               hook_shotorigin[2] = '8 8 -12';
-               hook_shotorigin[3] = '8 8 -12';
-       }
-       else
-       {
-               Weapon w = WEP_HOOK;
-               w.wr_init(w);
-               hook_shotorigin[0] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_HOOK.m_id), false, false, 1);
-               hook_shotorigin[1] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_HOOK.m_id), false, false, 2);
-               hook_shotorigin[2] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_HOOK.m_id), false, false, 3);
-               hook_shotorigin[3] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_HOOK.m_id), false, false, 4);
-       }
-}
diff --git a/qcsrc/server/g_hook.qh b/qcsrc/server/g_hook.qh
deleted file mode 100644 (file)
index 1ed78e2..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-
-// Wazat's grappling hook
-.entity                hook;
-void GrapplingHookThink(entity this);
-void RemoveGrapplingHooks(entity pl);
-void RemoveHook(entity this);
-// (note: you can change the hook impulse #'s to whatever you please)
-.float hook_time;
-
-.float hook_length;
-
-const float HOOK_FIRING = BIT(0);
-const float HOOK_REMOVING = BIT(1);
-const float HOOK_PULLING = BIT(2);
-const float HOOK_RELEASING = BIT(3);
-const float HOOK_WAITING_FOR_RELEASE = BIT(4);
-.float hook_state;
-.int state;
-
-void GrappleHookInit();
-vector hook_shotorigin[4];
-
diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc
deleted file mode 100644 (file)
index e258e35..0000000
+++ /dev/null
@@ -1,2266 +0,0 @@
-#include "g_world.qh"
-
-#include "anticheat.qh"
-#include "antilag.qh"
-#include "bot/api.qh"
-#include "campaign.qh"
-#include "cheats.qh"
-#include "client.qh"
-#include "command/common.qh"
-#include "command/getreplies.qh"
-#include "command/sv_cmd.qh"
-#include "command/vote.qh"
-#include "g_hook.qh"
-#include <server/gamelog.qh>
-#include <server/g_damage.qh>
-#include "ipban.qh"
-#include "mapvoting.qh"
-#include <server/mutators/_mod.qh>
-#include "race.qh"
-#include "scores.qh"
-#include "scores_rules.qh"
-#include "spawnpoints.qh"
-#include "teamplay.qh"
-#include "weapons/weaponstats.qh"
-#include <server/weapons/common.qh>
-#include "../common/constants.qh"
-#include <common/net_linked.qh>
-#include "../common/deathtypes/all.qh"
-#include <common/gamemodes/_mod.qh>
-#include "../common/gamemodes/sv_rules.qh"
-#include "../common/mapinfo.qh"
-#include "../common/monsters/_mod.qh"
-#include "../common/monsters/sv_monsters.qh"
-#include "../common/vehicles/all.qh"
-#include "../common/notifications/all.qh"
-#include "../common/physics/player.qh"
-#include "../common/playerstats.qh"
-#include "../common/stats.qh"
-#include "../common/teams.qh"
-#include <common/mapobjects/triggers.qh>
-#include "../common/mapobjects/trigger/secret.qh"
-#include "../common/mapobjects/target/music.qh"
-#include "../common/util.qh"
-#include "../common/items/_mod.qh"
-#include <common/weapons/_all.qh>
-#include "../common/state.qh"
-
-const float LATENCY_THINKRATE = 10;
-.float latency_sum;
-.float latency_cnt;
-.float latency_time;
-entity pingplreport;
-void PingPLReport_Think(entity this)
-{
-       float delta;
-       entity e;
-
-       delta = 3 / maxclients;
-       if(delta < sys_frametime)
-               delta = 0;
-       this.nextthink = time + delta;
-
-       e = edict_num(this.cnt + 1);
-       if(IS_CLIENT(e) && IS_REAL_CLIENT(e))
-       {
-               WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
-               WriteByte(MSG_BROADCAST, this.cnt);
-               WriteShort(MSG_BROADCAST, bound(1, CS(e).ping, 65535));
-               WriteByte(MSG_BROADCAST, min(ceil(CS(e).ping_packetloss * 255), 255));
-               WriteByte(MSG_BROADCAST, min(ceil(CS(e).ping_movementloss * 255), 255));
-
-               // record latency times for clients throughout the match so we can report it to playerstats
-               if(time > (CS(e).latency_time + LATENCY_THINKRATE))
-               {
-                       CS(e).latency_sum += CS(e).ping;
-                       CS(e).latency_cnt += 1;
-                       CS(e).latency_time = time;
-                       //print("sum: ", ftos(CS(e).latency_sum), ", cnt: ", ftos(CS(e).latency_cnt), ", avg: ", ftos(CS(e).latency_sum / CS(e).latency_cnt), ".\n");
-               }
-       }
-       else
-       {
-               WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
-               WriteByte(MSG_BROADCAST, this.cnt);
-               WriteShort(MSG_BROADCAST, 0);
-               WriteByte(MSG_BROADCAST, 0);
-               WriteByte(MSG_BROADCAST, 0);
-       }
-       this.cnt = (this.cnt + 1) % maxclients;
-}
-void PingPLReport_Spawn()
-{
-       pingplreport = new_pure(pingplreport);
-       setthink(pingplreport, PingPLReport_Think);
-       pingplreport.nextthink = time;
-}
-
-const float SPAWNFLAG_NO_WAYPOINTS_FOR_ITEMS = 1;
-string redirection_target;
-float world_initialized;
-
-void SetDefaultAlpha()
-{
-       if (!MUTATOR_CALLHOOK(SetDefaultAlpha))
-       {
-               default_player_alpha = autocvar_g_player_alpha;
-               if(default_player_alpha == 0)
-                       default_player_alpha = 1;
-               default_weapon_alpha = default_player_alpha;
-       }
-}
-
-void GotoFirstMap(entity this)
-{
-       float n;
-       if(autocvar__sv_init)
-       {
-               // cvar_set("_sv_init", "0");
-               // we do NOT set this to 0 any more, so someone "accidentally" changing
-               // to this "init" map on a dedicated server will cause no permanent
-               // harm
-               if(autocvar_g_maplist_shuffle)
-                       ShuffleMaplist();
-               n = tokenizebyseparator(autocvar_g_maplist, " ");
-               cvar_set("g_maplist_index", ftos(n - 1)); // jump to map 0 in GotoNextMap
-
-               MapInfo_Enumerate();
-               MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
-
-               if(!DoNextMapOverride(1))
-                       GotoNextMap(1);
-
-               return;
-       }
-
-       if(time < 5)
-       {
-               this.nextthink = time;
-       }
-       else
-       {
-               this.nextthink = time + 1;
-               LOG_INFO("Waiting for _sv_init being set to 1 by initialization scripts...");
-       }
-}
-
-void cvar_changes_init()
-{
-       float h;
-       string k, v, d;
-       float n, i, adding, pureadding;
-
-       strfree(cvar_changes);
-       strfree(cvar_purechanges);
-       cvar_purechanges_count = 0;
-
-       h = buf_create();
-       buf_cvarlist(h, "", "_"); // exclude all _ cvars as they are temporary
-       n = buf_getsize(h);
-
-       adding = true;
-       pureadding = true;
-
-       for(i = 0; i < n; ++i)
-       {
-               k = bufstr_get(h, i);
-
-#define BADPREFIX(p) if(substring(k, 0, strlen(p)) == p) continue
-#define BADPRESUFFIX(p,s) if(substring(k, 0, strlen(p)) == p && substring(k, -strlen(s), -1) == s) continue
-#define BADCVAR(p) if(k == p) continue
-
-               // general excludes and namespaces for server admin used cvars
-               BADPREFIX("help_"); // PN's server has this listed as changed, let's not rat him out for THAT
-
-               // internal
-               BADPREFIX("csqc_");
-               BADPREFIX("cvar_check_");
-               BADCVAR("gamecfg");
-               BADCVAR("g_configversion");
-               BADCVAR("halflifebsp");
-               BADCVAR("sv_mapformat_is_quake2");
-               BADCVAR("sv_mapformat_is_quake3");
-               BADPREFIX("sv_world");
-
-               // client
-               BADPREFIX("chase_");
-               BADPREFIX("cl_");
-               BADPREFIX("con_");
-               BADPREFIX("scoreboard_");
-               BADPREFIX("g_campaign");
-               BADPREFIX("g_waypointsprite_");
-               BADPREFIX("gl_");
-               BADPREFIX("joy");
-               BADPREFIX("hud_");
-               BADPREFIX("m_");
-               BADPREFIX("menu_");
-               BADPREFIX("net_slist_");
-               BADPREFIX("r_");
-               BADPREFIX("sbar_");
-               BADPREFIX("scr_");
-               BADPREFIX("snd_");
-               BADPREFIX("show");
-               BADPREFIX("sensitivity");
-               BADPREFIX("userbind");
-               BADPREFIX("v_");
-               BADPREFIX("vid_");
-               BADPREFIX("crosshair");
-               BADCVAR("mod_q3bsp_lightmapmergepower");
-               BADCVAR("mod_q3bsp_nolightmaps");
-               BADCVAR("fov");
-               BADCVAR("mastervolume");
-               BADCVAR("volume");
-               BADCVAR("bgmvolume");
-               BADCVAR("in_pitch_min");
-               BADCVAR("in_pitch_max");
-
-               // private
-               BADCVAR("developer");
-               BADCVAR("log_dest_udp");
-               BADCVAR("net_address");
-               BADCVAR("net_address_ipv6");
-               BADCVAR("port");
-               BADCVAR("savedgamecfg");
-               BADCVAR("serverconfig");
-               BADCVAR("sv_autoscreenshot");
-               BADCVAR("sv_heartbeatperiod");
-               BADCVAR("sv_vote_master_password");
-               BADCVAR("sys_colortranslation");
-               BADCVAR("sys_specialcharactertranslation");
-               BADCVAR("timeformat");
-               BADCVAR("timestamps");
-               BADCVAR("g_require_stats");
-               BADPREFIX("developer_");
-               BADPREFIX("g_ban_");
-               BADPREFIX("g_banned_list");
-               BADPREFIX("g_require_stats_");
-               BADPREFIX("g_chat_flood_");
-               BADPREFIX("g_ghost_items");
-               BADPREFIX("g_playerstats_");
-               BADPREFIX("g_voice_flood_");
-               BADPREFIX("log_file");
-               BADPREFIX("quit_");
-               BADPREFIX("rcon_");
-               BADPREFIX("sv_allowdownloads");
-               BADPREFIX("sv_autodemo");
-               BADPREFIX("sv_curl_");
-               BADPREFIX("sv_eventlog");
-               BADPREFIX("sv_logscores_");
-               BADPREFIX("sv_master");
-               BADPREFIX("sv_weaponstats_");
-               BADPREFIX("sv_waypointsprite_");
-               BADCVAR("rescan_pending");
-
-               // these can contain player IDs, so better hide
-               BADPREFIX("g_forced_team_");
-               BADCVAR("sv_muteban_list");
-               BADCVAR("sv_voteban_list");
-               BADCVAR("sv_allow_customplayermodels_idlist");
-               BADCVAR("sv_allow_customplayermodels_speciallist");
-
-               // mapinfo
-               BADCVAR("fraglimit");
-               BADCVAR("g_arena");
-               BADCVAR("g_assault");
-               BADCVAR("g_ca");
-               BADCVAR("g_ca_teams");
-               BADCVAR("g_conquest");
-               BADCVAR("g_conquest_teams");
-               BADCVAR("g_ctf");
-               BADCVAR("g_cts");
-               BADCVAR("g_dotc");
-               BADCVAR("g_dm");
-               BADCVAR("g_domination");
-               BADCVAR("g_domination_default_teams");
-               BADCVAR("g_duel");
-               BADCVAR("g_duel_not_dm_maps");
-               BADCVAR("g_freezetag");
-               BADCVAR("g_freezetag_teams");
-               BADCVAR("g_invasion_teams");
-               BADCVAR("g_invasion_type");
-               BADCVAR("g_jailbreak");
-               BADCVAR("g_jailbreak_teams");
-               BADCVAR("g_keepaway");
-               BADCVAR("g_keyhunt");
-               BADCVAR("g_keyhunt_teams");
-               BADCVAR("g_lms");
-               BADCVAR("g_nexball");
-               BADCVAR("g_onslaught");
-               BADCVAR("g_race");
-               BADCVAR("g_race_laps_limit");
-               BADCVAR("g_race_qualifying_timelimit");
-               BADCVAR("g_race_qualifying_timelimit_override");
-               BADCVAR("g_runematch");
-               BADCVAR("g_shootfromeye");
-               BADCVAR("g_snafu");
-               BADCVAR("g_survival");
-               BADCVAR("g_survival_not_dm_maps");
-               BADCVAR("g_tdm");
-               BADCVAR("g_tdm_on_dm_maps");
-               BADCVAR("g_tdm_teams");
-               BADCVAR("g_vip");
-               BADCVAR("leadlimit");
-               BADCVAR("nextmap");
-               BADCVAR("teamplay");
-               BADCVAR("timelimit");
-               BADCVAR("g_mapinfo_settemp_acl");
-               BADCVAR("g_mapinfo_ignore_warnings");
-               BADCVAR("g_maplist_ignore_sizes");
-               BADCVAR("g_maplist_sizes_count_bots");
-
-               // long
-               BADCVAR("hostname");
-               BADCVAR("g_maplist");
-               BADCVAR("g_maplist_mostrecent");
-               BADCVAR("sv_motd");
-
-               v = cvar_string(k);
-               d = cvar_defstring(k);
-               if(v == d)
-                       continue;
-
-               if(adding)
-               {
-                       cvar_changes = strcat(cvar_changes, k, " \"", v, "\" // \"", d, "\"\n");
-                       if(strlen(cvar_changes) > 16384)
-                       {
-                               cvar_changes = "// too many settings have been changed to show them here\n";
-                               adding = 0;
-                       }
-               }
-
-               // now check if the changes are actually gameplay relevant
-
-               // does nothing gameplay relevant
-               BADCVAR("captureleadlimit_override");
-               BADCVAR("condump_stripcolors");
-               BADCVAR("gameversion");
-               BADCVAR("fs_gamedir");
-               BADCVAR("g_allow_oldvortexbeam");
-               BADCVAR("g_balance_kill_delay");
-               BADCVAR("g_buffs_pickup_anyway");
-               BADCVAR("g_buffs_randomize");
-               BADCVAR("g_buffs_randomize_teamplay");
-               BADCVAR("g_campcheck_distance");
-               BADCVAR("g_chatsounds");
-               BADCVAR("g_ca_point_leadlimit");
-               BADCVAR("g_ca_point_limit");
-               BADCVAR("g_ctf_captimerecord_always");
-               BADCVAR("g_ctf_flag_glowtrails");
-               BADCVAR("g_ctf_dynamiclights");
-               BADCVAR("g_ctf_flag_pickup_verbosename");
-               BADPRESUFFIX("g_ctf_flag_", "_model");
-               BADPRESUFFIX("g_ctf_flag_", "_skin");
-               BADCVAR("g_domination_point_leadlimit");
-               BADCVAR("g_forced_respawn");
-               BADCVAR("g_freezetag_point_leadlimit");
-               BADCVAR("g_freezetag_point_limit");
-               BADCVAR("g_glowtrails");
-               BADCVAR("g_hats");
-               BADCVAR("g_casings");
-               BADCVAR("g_invasion_point_limit");
-               BADCVAR("g_jump_grunt");
-               BADCVAR("g_keepaway_ballcarrier_effects");
-               BADCVAR("g_keepawayball_effects");
-               BADCVAR("g_keyhunt_point_leadlimit");
-               BADCVAR("g_nexball_goalleadlimit");
-               BADCVAR("g_new_toys_autoreplace");
-               BADCVAR("g_new_toys_use_pickupsound");
-               BADCVAR("g_physics_predictall");
-               BADCVAR("g_piggyback");
-               BADCVAR("g_playerclip_collisions");
-               BADCVAR("g_spawn_alloweffects");
-               BADCVAR("g_tdm_point_leadlimit");
-               BADCVAR("g_tdm_point_limit");
-               BADCVAR("leadlimit_and_fraglimit");
-               BADCVAR("leadlimit_override");
-               BADCVAR("pausable");
-               BADCVAR("sv_announcer");
-               BADCVAR("sv_checkforpacketsduringsleep");
-               BADCVAR("sv_damagetext");
-               BADCVAR("sv_db_saveasdump");
-               BADCVAR("sv_intermission_cdtrack");
-               BADCVAR("sv_mapchange_delay");
-               BADCVAR("sv_minigames");
-               BADCVAR("sv_namechangetimer");
-               BADCVAR("sv_precacheplayermodels");
-               BADCVAR("sv_radio");
-               BADCVAR("sv_stepheight");
-               BADCVAR("sv_timeout");
-               BADCVAR("sv_weapons_modeloverride");
-               BADCVAR("w_prop_interval");
-               BADPREFIX("chat_");
-               BADPREFIX("crypto_");
-               BADPREFIX("gameversion_");
-               BADPREFIX("g_chat_");
-               BADPREFIX("g_ctf_captimerecord_");
-               BADPREFIX("g_hats_");
-               BADPREFIX("g_maplist_");
-               BADPREFIX("g_mod_");
-               BADPREFIX("g_respawn_");
-               BADPREFIX("net_");
-               BADPREFIX("notification_");
-               BADPREFIX("prvm_");
-               BADPREFIX("skill_");
-               BADPREFIX("sv_allow_");
-               BADPREFIX("sv_cullentities_");
-               BADPREFIX("sv_maxidle_");
-               BADPREFIX("sv_minigames_");
-               BADPREFIX("sv_radio_");
-               BADPREFIX("sv_timeout_");
-               BADPREFIX("sv_vote_");
-               BADPREFIX("timelimit_");
-
-               // allowed changes to server admins (please sync this to server.cfg)
-               // vi commands:
-               //   :/"impure"/,$d
-               //   :g!,^\/\/[^ /],d
-               //   :%s,//\([^ ]*\).*,BADCVAR("\1");,
-               //   :%!sort
-               // yes, this does contain some redundant stuff, don't really care
-               BADPREFIX("bot_ai_");
-               BADCVAR("bot_config_file");
-               BADCVAR("bot_number");
-               BADCVAR("bot_prefix");
-               BADCVAR("bot_suffix");
-               BADCVAR("capturelimit_override");
-               BADCVAR("fraglimit_override");
-               BADCVAR("gametype");
-               BADCVAR("g_antilag");
-               BADCVAR("g_balance_teams");
-               BADCVAR("g_balance_teams_prevent_imbalance");
-               BADCVAR("g_balance_teams_scorefactor");
-               BADCVAR("g_ban_sync_trusted_servers");
-               BADCVAR("g_ban_sync_uri");
-               BADCVAR("g_buffs");
-               BADCVAR("g_ca_teams_override");
-               BADCVAR("g_ctf_fullbrightflags");
-               BADCVAR("g_ctf_ignore_frags");
-               BADCVAR("g_ctf_leaderboard");
-               BADCVAR("g_domination_point_limit");
-               BADCVAR("g_domination_teams_override");
-               BADCVAR("g_freezetag_teams_override");
-               BADCVAR("g_friendlyfire");
-               BADCVAR("g_fullbrightitems");
-               BADCVAR("g_fullbrightplayers");
-               BADCVAR("g_keyhunt_point_limit");
-               BADCVAR("g_keyhunt_teams_override");
-               BADCVAR("g_lms_lives_override");
-               BADCVAR("g_maplist");
-               BADCVAR("g_maxplayers");
-               BADCVAR("g_mirrordamage");
-               BADCVAR("g_nexball_goallimit");
-               BADCVAR("g_norecoil");
-               BADCVAR("g_physics_clientselect");
-               BADCVAR("g_pinata");
-               BADCVAR("g_powerups");
-               BADCVAR("g_player_brightness");
-               BADCVAR("g_rocket_flying");
-               BADCVAR("g_rocket_flying_disabledelays");
-               BADCVAR("g_spawnshieldtime");
-               BADCVAR("g_start_delay");
-               BADCVAR("g_superspectate");
-               BADCVAR("g_tdm_teams_override");
-               BADCVAR("g_warmup");
-               BADCVAR("g_weapon_stay"); BADPRESUFFIX("g_", "_weapon_stay");
-               BADCVAR("hostname");
-               BADCVAR("log_file");
-               BADCVAR("maxplayers");
-               BADCVAR("minplayers");
-               BADCVAR("minplayers_per_team");
-               BADCVAR("net_address");
-               BADCVAR("port");
-               BADCVAR("rcon_password");
-               BADCVAR("rcon_restricted_commands");
-               BADCVAR("rcon_restricted_password");
-               BADCVAR("skill");
-               BADCVAR("sv_adminnick");
-               BADCVAR("sv_autoscreenshot");
-               BADCVAR("sv_autotaunt");
-               BADCVAR("sv_curl_defaulturl");
-               BADCVAR("sv_defaultcharacter");
-               BADCVAR("sv_defaultcharacterskin");
-               BADCVAR("sv_defaultplayercolors");
-               BADCVAR("sv_defaultplayermodel");
-               BADCVAR("sv_defaultplayerskin");
-               BADCVAR("sv_maxidle");
-               BADCVAR("sv_maxrate");
-               BADCVAR("sv_motd");
-               BADCVAR("sv_public");
-               BADCVAR("sv_ready_restart");
-               BADCVAR("sv_status_privacy");
-               BADCVAR("sv_taunt");
-               BADCVAR("sv_vote_call");
-               BADCVAR("sv_vote_commands");
-               BADCVAR("sv_vote_majority_factor");
-               BADCVAR("sv_vote_master");
-               BADCVAR("sv_vote_master_commands");
-               BADCVAR("sv_vote_master_password");
-               BADCVAR("sv_vote_simple_majority_factor");
-               BADCVAR("teamplay_mode");
-               BADCVAR("timelimit_override");
-               BADPREFIX("g_warmup_");
-               BADPREFIX("sv_info_");
-               BADPREFIX("sv_ready_restart_");
-
-               // mutators that announce themselves properly to the server browser
-               BADCVAR("g_instagib");
-               BADCVAR("g_new_toys");
-               BADCVAR("g_nix");
-               BADCVAR("g_grappling_hook");
-               BADCVAR("g_jetpack");
-
-               // temporary for testing
-               // TODO remove before 0.8.3 release
-               BADCVAR("g_ca_weaponarena");
-               BADCVAR("g_freezetag_weaponarena");
-               BADCVAR("g_lms_weaponarena");
-               BADCVAR("g_ctf_stalemate_time");
-
-               if(cvar_string("g_mod_balance") == "Testing")
-               {
-                       // (temporary) while using the Testing balance, any weapon balance cvars are allowed to be changed
-                       BADPREFIX("g_balance_");
-               }
-
-#undef BADPRESUFFIX
-#undef BADPREFIX
-#undef BADCVAR
-
-               if(pureadding)
-               {
-                       cvar_purechanges = strcat(cvar_purechanges, k, " \"", v, "\" // \"", d, "\"\n");
-                       if(strlen(cvar_purechanges) > 16384)
-                       {
-                               cvar_purechanges = "// too many settings have been changed to show them here\n";
-                               pureadding = 0;
-                       }
-               }
-               ++cvar_purechanges_count;
-               // WARNING: this variable is used for the server list
-               // NEVER dare to skip this code!
-               // Hacks to intentionally appearing as "pure server" even though you DO have
-               // modified settings may be punished by removal from the server list.
-               // You can do to the variables cvar_changes and cvar_purechanges all you want,
-               // though.
-       }
-       buf_del(h);
-       if(cvar_changes == "")
-               cvar_changes = "// this server runs at default server settings\n";
-       else
-               cvar_changes = strcat("// this server runs at modified server settings:\n", cvar_changes);
-       cvar_changes = strzone(cvar_changes);
-       if(cvar_purechanges == "")
-               cvar_purechanges = "// this server runs at default gameplay settings\n";
-       else
-               cvar_purechanges = strcat("// this server runs at modified gameplay settings:\n", cvar_purechanges);
-       cvar_purechanges = strzone(cvar_purechanges);
-}
-
-entity randomseed;
-bool RandomSeed_Send(entity this, entity to, int sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_RANDOMSEED);
-       WriteShort(MSG_ENTITY, this.cnt);
-       return true;
-}
-void RandomSeed_Think(entity this)
-{
-       this.cnt = bound(0, floor(random() * 65536), 65535);
-       this.nextthink = time + 5;
-
-       this.SendFlags |= 1;
-}
-void RandomSeed_Spawn()
-{
-       randomseed = new_pure(randomseed);
-       setthink(randomseed, RandomSeed_Think);
-       Net_LinkEntity(randomseed, false, 0, RandomSeed_Send);
-
-       getthink(randomseed)(randomseed); // sets random seed and nextthink
-}
-
-spawnfunc(__init_dedicated_server)
-{
-       // handler for _init/_init map (only for dedicated server initialization)
-
-       world_initialized = -1; // don't complain
-
-       delete_fn = remove_unsafely;
-
-       entity e = spawn();
-       setthink(e, GotoFirstMap);
-       e.nextthink = time; // this is usually 1 at this point
-
-       e = new(info_player_deathmatch);  // safeguard against player joining
-
-    // assign reflectively to avoid "assignment to world" warning
-    for (int i = 0, n = numentityfields(); i < n; ++i) {
-        string k = entityfieldname(i);
-        if (k == "classname") {
-            // safeguard against various stuff ;)
-            putentityfieldstring(i, this, "worldspawn");
-            break;
-        }
-    }
-
-       // needs to be done so early because of the constants they create
-       static_init();
-       static_init_late();
-       static_init_precache();
-
-       IL_PUSH(g_spawnpoints, e); // just incase
-
-       MapInfo_Enumerate();
-       MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
-}
-
-void __init_dedicated_server_shutdown() {
-       MapInfo_Shutdown();
-}
-
-STATIC_INIT_EARLY(maxclients)
-{
-       maxclients = 0;
-       for (entity head = nextent(NULL); head; head = nextent(head)) {
-               ++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)
-{
-       server_is_dedicated = boolean(stof(cvar_defstring("is_dedicated")));
-
-       bool wantrestart = false;
-       {
-               if (!server_is_dedicated)
-               {
-                       // force unloading of server pk3 files when starting a listen server
-                       // localcmd("\nfs_rescan\n"); // FIXME: does more harm than good, has unintended side effects. What we really want is to unload temporary pk3s only
-                       // restore csqc_progname too
-                       string expect = "csprogs.dat";
-                       wantrestart = cvar_string("csqc_progname") != expect;
-                       cvar_set("csqc_progname", expect);
-               }
-               else
-               {
-                       // Try to use versioned csprogs from pk3
-                       // Only ever use versioned csprogs.dat files on dedicated servers;
-                       // we need to reset csqc_progname on clients ourselves, and it's easier if the client's release name is constant
-                       string pk3csprogs = "csprogs-" WATERMARK ".dat";
-                       // This always works; fall back to it if a versioned csprogs.dat is suddenly missing
-                       string select = "csprogs.dat";
-                       if (fexists(pk3csprogs)) select = pk3csprogs;
-                       if (cvar_string("csqc_progname") != select)
-                       {
-                               cvar_set("csqc_progname", select);
-                               wantrestart = true;
-                       }
-                       // Check for updates on startup
-                       // We do it this way for atomicity so that connecting clients still match the server progs and don't disconnect
-                       int sentinel = fopen("progs.txt", FILE_READ);
-                       if (sentinel >= 0)
-                       {
-                               string switchversion = fgets(sentinel);
-                               fclose(sentinel);
-                               if (switchversion != "" && switchversion != WATERMARK)
-                               {
-                                       LOG_INFOF("Switching progs: " WATERMARK " -> %s", switchversion);
-                                       // if it doesn't exist, assume either:
-                                       //   a) the current program was overwritten
-                                       //   b) this is a client only update
-                                       string newprogs = sprintf("progs-%s.dat", switchversion);
-                                       if (fexists(newprogs))
-                                       {
-                                               cvar_set("sv_progs", newprogs);
-                                               wantrestart = true;
-                                       }
-                                       string newcsprogs = sprintf("csprogs-%s.dat", switchversion);
-                                       if (fexists(newcsprogs))
-                                       {
-                                               cvar_set("csqc_progname", newcsprogs);
-                                               wantrestart = true;
-                                       }
-                               }
-                       }
-               }
-               if (wantrestart)
-               {
-                       LOG_INFO("Restart requested");
-                       changelevel(mapname);
-                       // let initialization continue, shutdown depends on it
-               }
-       }
-
-       if(world_already_spawned)
-               error("world already spawned - you may have EXACTLY ONE worldspawn!");
-       world_already_spawned = true;
-
-       delete_fn = remove_safely; // during spawning, watch what you remove!
-
-       cvar_changes_init(); // do this very early now so it REALLY matches the server config
-
-       // needs to be done so early because of the constants they create
-       static_init();
-
-       ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid));
-
-       TemporaryDB = db_create();
-
-       // 0 normal
-       lightstyle(0, "m");
-
-       // 1 FLICKER (first variety)
-       lightstyle(1, "mmnmmommommnonmmonqnmmo");
-
-       // 2 SLOW STRONG PULSE
-       lightstyle(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba");
-
-       // 3 CANDLE (first variety)
-       lightstyle(3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg");
-
-       // 4 FAST STROBE
-       lightstyle(4, "mamamamamama");
-
-       // 5 GENTLE PULSE 1
-       lightstyle(5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj");
-
-       // 6 FLICKER (second variety)
-       lightstyle(6, "nmonqnmomnmomomno");
-
-       // 7 CANDLE (second variety)
-       lightstyle(7, "mmmaaaabcdefgmmmmaaaammmaamm");
-
-       // 8 CANDLE (third variety)
-       lightstyle(8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa");
-
-       // 9 SLOW STROBE (fourth variety)
-       lightstyle(9, "aaaaaaaazzzzzzzz");
-
-       // 10 FLUORESCENT FLICKER
-       lightstyle(10, "mmamammmmammamamaaamammma");
-
-       // 11 SLOW PULSE NOT FADE TO BLACK
-       lightstyle(11, "abcdefghijklmnopqrrqponmlkjihgfedcba");
-
-       // styles 32-62 are assigned by the spawnfunc_light program for switchable lights
-
-       // 63 testing
-       lightstyle(63, "a");
-
-       if(autocvar_g_campaign)
-               CampaignPreInit();
-
-       Map_MarkAsRecent(mapname);
-
-       PlayerStats_GameReport_Init(); // we need this to be initiated before InitGameplayMode
-
-       InitGameplayMode();
-       static_init_late();
-       static_init_precache();
-       readlevelcvars();
-       GrappleHookInit();
-
-       GameRules_limit_fallbacks();
-
-       if(warmup_limit == 0)
-               warmup_limit = (autocvar_timelimit > 0) ? autocvar_timelimit * 60 : autocvar_timelimit;
-
-       player_count = 0;
-       bot_waypoints_for_items = autocvar_g_waypoints_for_items;
-       if(bot_waypoints_for_items == 1)
-               if(this.spawnflags & SPAWNFLAG_NO_WAYPOINTS_FOR_ITEMS)
-                       bot_waypoints_for_items = 0;
-
-       WaypointSprite_Init();
-
-       GameLogInit(); // prepare everything
-       // NOTE for matchid:
-       // changing the logic generating it is okay. But:
-       // it HAS to stay <= 64 chars
-       // character set: ASCII 33-126 without the following characters: : ; ' " \ $
-       if(autocvar_sv_eventlog)
-       {
-               string s = sprintf("%s.%s.%06d", itos(autocvar_sv_eventlog_files_counter), strftime(false, "%s"), floor(random() * 1000000));
-               matchid = strzone(s);
-
-               GameLogEcho(strcat(":gamestart:", GetGametype(), "_", GetMapname(), ":", s));
-               s = ":gameinfo:mutators:LIST";
-
-               MUTATOR_CALLHOOK(BuildMutatorsString, s);
-               s = M_ARGV(0, string);
-
-               // initialiation stuff, not good in the mutator system
-               if(!autocvar_g_use_ammunition)
-                       s = strcat(s, ":no_use_ammunition");
-
-               // initialiation stuff, not good in the mutator system
-               if(autocvar_g_pickup_items == 0)
-                       s = strcat(s, ":no_pickup_items");
-               if(autocvar_g_pickup_items > 0)
-                       s = strcat(s, ":pickup_items");
-
-               // initialiation stuff, not good in the mutator system
-               if(autocvar_g_weaponarena != "0")
-                       s = strcat(s, ":", autocvar_g_weaponarena, " arena");
-
-               // TODO to mutator system
-               if(autocvar_g_norecoil)
-                       s = strcat(s, ":norecoil");
-
-               // TODO to mutator system
-               if(autocvar_g_powerups == 0)
-                       s = strcat(s, ":no_powerups");
-               if(autocvar_g_powerups > 0)
-                       s = strcat(s, ":powerups");
-
-               GameLogEcho(s);
-               GameLogEcho(":gameinfo:end");
-       }
-       else
-               matchid = strzone(ftos(random()));
-
-       cvar_set("nextmap", "");
-
-       SetDefaultAlpha();
-
-       if(autocvar_g_campaign)
-               CampaignPostInit();
-
-       Ban_LoadBans();
-
-       MapInfo_Enumerate();
-       MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1);
-
-       if(fexists(strcat("scripts/", mapname, ".arena")))
-               cvar_settemp("sv_q3acompat_machineshotgunswap", "1");
-
-       if(fexists(strcat("scripts/", mapname, ".defi")))
-               cvar_settemp("sv_q3defragcompat", "1");
-
-       if(whichpack(strcat("maps/", mapname, ".cfg")) != "")
-       {
-               int fd = fopen(strcat("maps/", mapname, ".cfg"), FILE_READ);
-               if(fd != -1)
-               {
-                       string s;
-                       while((s = fgets(fd)))
-                       {
-                               int l = tokenize_console(s);
-                               if(l < 2)
-                                       continue;
-                               if(argv(0) == "cd")
-                               {
-                                       string trackname = argv(2);
-                                       LOG_INFO("Found ^1UNSUPPORTED^7 cd loop command in .cfg file; put this line in mapinfo instead:");
-                                       LOG_INFO("  cdtrack ", trackname);
-                                       if (cvar_value_issafe(trackname))
-                                       {
-                                               string newstuff = strcat(clientstuff, "cd loop \"", trackname, "\"\n");
-                                               strcpy(clientstuff, newstuff);
-                                       }
-                               }
-                               else if(argv(0) == "fog")
-                               {
-                                       LOG_INFO("Found ^1UNSUPPORTED^7 fog command in .cfg file; put this line in worldspawn in the .map/.bsp/.ent file instead:");
-                                       LOG_INFO("  \"fog\" \"", s, "\"");
-                               }
-                               else if(argv(0) == "set")
-                               {
-                                       LOG_INFO("Found ^1UNSUPPORTED^7 set command in .cfg file; put this line in mapinfo instead:");
-                                       LOG_INFO("  clientsettemp_for_type all ", argv(1), " ", argv(2));
-                               }
-                               else if(argv(0) != "//")
-                               {
-                                       LOG_INFO("Found ^1UNSUPPORTED^7 set command in .cfg file; put this line in mapinfo instead:");
-                                       LOG_INFO("  clientsettemp_for_type all ", argv(0), " ", argv(1));
-                               }
-                       }
-                       fclose(fd);
-               }
-       }
-
-       WeaponStats_Init();
-
-       Nagger_Init();
-
-       // set up information replies for clients and server to use
-       maplist_reply = strzone(getmaplist());
-       lsmaps_reply = strzone(getlsmaps());
-       monsterlist_reply = strzone(getmonsterlist());
-       for(int i = 0; i < 10; ++i)
-       {
-               string s = getrecords(i);
-               if (s)
-                       records_reply[i] = strzone(s);
-       }
-       ladder_reply = strzone(getladder());
-       rankings_reply = strzone(getrankings());
-
-       // begin other init
-       ClientInit_Spawn();
-       RandomSeed_Spawn();
-       PingPLReport_Spawn();
-
-       CheatInit();
-
-       if (!wantrestart) localcmd("\n_sv_hook_gamestart ", GetGametype(), "\n");
-
-       // fill sv_curl_serverpackages from .serverpackage files
-       if (autocvar_sv_curl_serverpackages_auto)
-       {
-               string s = "csprogs-" WATERMARK ".txt";
-               // remove automatically managed files from the list to prevent duplicates
-               for (int i = 0, n = tokenize_console(cvar_string("sv_curl_serverpackages")); i < n; ++i)
-               {
-                       string pkg = argv(i);
-                       if (startsWith(pkg, "csprogs-")) continue;
-                       if (endsWith(pkg, "-serverpackage.txt")) continue;
-                       if (endsWith(pkg, ".serverpackage")) continue;  // OLD legacy
-                       s = cons(s, pkg);
-               }
-               // add automatically managed files to the list
-               #define X(match) MACRO_BEGIN \
-                       int fd = search_begin(match, true, false); \
-                       if (fd >= 0) \
-                       { \
-                               for (int i = 0, j = search_getsize(fd); i < j; ++i) \
-                               { \
-                                       s = cons(s, search_getfilename(fd, i)); \
-                               } \
-                               search_end(fd); \
-                       } \
-               MACRO_END
-               X("*-serverpackage.txt");
-               X("*.serverpackage");
-               #undef X
-               cvar_set("sv_curl_serverpackages", s);
-       }
-
-       // MOD AUTHORS: change this, and possibly remove a few of the blocks below to ignore certain changes
-       modname = "Xonotic";
-       // physics/balance/config changes that count as mod
-       if(cvar_string("g_mod_physics") != cvar_defstring("g_mod_physics"))
-               modname = cvar_string("g_mod_physics");
-       if(cvar_string("g_mod_balance") != cvar_defstring("g_mod_balance") && cvar_string("g_mod_balance") != "Testing")
-               modname = cvar_string("g_mod_balance");
-       if(cvar_string("g_mod_config") != cvar_defstring("g_mod_config"))
-               modname = cvar_string("g_mod_config");
-       // extra mutators that deserve to count as mod
-       MUTATOR_CALLHOOK(SetModname, modname);
-       modname = M_ARGV(0, string);
-
-       // save it for later
-       modname = strzone(modname);
-
-       WinningConditionHelper(this); // set worldstatus
-
-       world_initialized = 1;
-       __spawnfunc_spawn_all();
-}
-
-spawnfunc(light)
-{
-       //makestatic (this); // Who the f___ did that?
-       delete(this);
-}
-
-string GetGametype()
-{
-       return MapInfo_Type_ToString(MapInfo_LoadedGametype);
-}
-
-string GetMapname()
-{
-       return mapname;
-}
-
-float Map_Count, Map_Current;
-string Map_Current_Name;
-
-// NOTE: this now expects the map list to be already tokenized and the count in Map_Count
-int GetMaplistPosition()
-{
-       string map = GetMapname();
-       int idx = autocvar_g_maplist_index;
-
-       if(idx >= 0)
-       {
-               if(idx < Map_Count)
-               {
-                       if(map == argv(idx))
-                       {
-                               return idx;
-                       }
-               }
-       }
-
-       for(int pos = 0; pos < Map_Count; ++pos)
-       {
-               if(map == argv(pos))
-                       return pos;
-       }
-
-       // resume normal maplist rotation if current map is not in g_maplist
-       return idx;
-}
-
-bool MapHasRightSize(string map)
-{
-       int minplayers = max(0, floor(autocvar_minplayers));
-       if (teamplay)
-               minplayers = max(0, floor(autocvar_minplayers_per_team) * AvailableTeams());
-       if (autocvar_g_maplist_check_waypoints
-               && (currentbots || autocvar_bot_number || player_count < minplayers))
-       {
-               string checkwp_msg = strcat("checkwp ", map);
-               if(!fexists(strcat("maps/", map, ".waypoints")))
-               {
-                       LOG_TRACE(checkwp_msg, ": no waypoints");
-                       return false;
-               }
-               LOG_TRACE(checkwp_msg, ": has waypoints");
-       }
-
-       if(autocvar_g_maplist_ignore_sizes)
-               return true;
-
-       // open map size restriction file
-       string opensize_msg = strcat("opensize ", map);
-       float fh = fopen(strcat("maps/", map, ".sizes"), FILE_READ);
-       int player_limit = ((autocvar_g_maplist_sizes_count_maxplayers) ? GetPlayerLimit() : 0);
-       int pcount = ((player_limit > 0) ? min(player_count, player_limit) : player_count); // bind it to the player limit so that forced spectators don't influence the limits
-       if(!autocvar_g_maplist_sizes_count_bots)
-               pcount -= currentbots;
-       if(fh >= 0)
-       {
-               opensize_msg = strcat(opensize_msg, ": ok, ");
-               int mapmin = stoi(fgets(fh));
-               int mapmax = stoi(fgets(fh));
-               fclose(fh);
-               if(pcount < mapmin)
-               {
-                       LOG_TRACE(opensize_msg, "not enough");
-                       return false;
-               }
-               if(mapmax && pcount > mapmax)
-               {
-                       LOG_TRACE(opensize_msg, "too many");
-                       return false;
-               }
-               LOG_TRACE(opensize_msg, "right size");
-               return true;
-       }
-       LOG_TRACE(opensize_msg, ": not found");
-       return true;
-}
-
-string Map_Filename(float position)
-{
-       return strcat("maps/", argv(position), ".bsp");
-}
-
-void Map_MarkAsRecent(string m)
-{
-       cvar_set("g_maplist_mostrecent", strwords(cons(m, autocvar_g_maplist_mostrecent), max(0, autocvar_g_maplist_mostrecent_count)));
-}
-
-float Map_IsRecent(string m)
-{
-       return strhasword(autocvar_g_maplist_mostrecent, m);
-}
-
-float Map_Check(float position, float pass)
-{
-       string filename;
-       string map_next;
-       map_next = argv(position);
-       if(pass <= 1)
-       {
-               if(Map_IsRecent(map_next))
-                       return 0;
-       }
-       filename = Map_Filename(position);
-       if(MapInfo_CheckMap(map_next))
-       {
-               if(pass == 2)
-                       return 1;
-               if(MapHasRightSize(map_next))
-                       return 1;
-               return 0;
-       }
-       else
-               LOG_DEBUG( "Couldn't select '", filename, "'..." );
-
-       return 0;
-}
-
-void Map_Goto_SetStr(string nextmapname)
-{
-       if(getmapname_stored != "")
-               strunzone(getmapname_stored);
-       if(nextmapname == "")
-               getmapname_stored = "";
-       else
-               getmapname_stored = strzone(nextmapname);
-}
-
-void Map_Goto_SetFloat(float position)
-{
-       cvar_set("g_maplist_index", ftos(position));
-       Map_Goto_SetStr(argv(position));
-}
-
-void Map_Goto(float reinit)
-{
-       MapInfo_LoadMap(getmapname_stored, reinit);
-}
-
-// return codes of map selectors:
-//   -1 = temporary failure (that is, try some method that is guaranteed to succeed)
-//   -2 = permanent failure
-float MaplistMethod_Iterate() // usual method
-{
-       float pass, i;
-
-       LOG_TRACE("Trying MaplistMethod_Iterate");
-
-       for(pass = 1; pass <= 2; ++pass)
-       {
-               for(i = 1; i < Map_Count; ++i)
-               {
-                       float mapindex;
-                       mapindex = (i + Map_Current) % Map_Count;
-                       if(Map_Check(mapindex, pass))
-                               return mapindex;
-               }
-       }
-       return -1;
-}
-
-float MaplistMethod_Repeat() // fallback method
-{
-       LOG_TRACE("Trying MaplistMethod_Repeat");
-
-       if(Map_Check(Map_Current, 2))
-               return Map_Current;
-       return -2;
-}
-
-float MaplistMethod_Random() // random map selection
-{
-       float i, imax;
-
-       LOG_TRACE("Trying MaplistMethod_Random");
-
-       imax = 42;
-
-       for(i = 0; i <= imax; ++i)
-       {
-               float mapindex;
-               mapindex = (Map_Current + floor(random() * (Map_Count - 1) + 1)) % Map_Count; // any OTHER map
-               if(Map_Check(mapindex, 1))
-                       return mapindex;
-       }
-       return -1;
-}
-
-float MaplistMethod_Shuffle(float exponent) // more clever shuffling
-// the exponent sets a bias on the map selection:
-// the higher the exponent, the less likely "shortly repeated" same maps are
-{
-       float i, j, imax, insertpos;
-
-       LOG_TRACE("Trying MaplistMethod_Shuffle");
-
-       imax = 42;
-
-       for(i = 0; i <= imax; ++i)
-       {
-               string newlist;
-
-               // now reinsert this at another position
-               insertpos = (random() ** (1 / exponent));       // ]0, 1]
-               insertpos = insertpos * (Map_Count - 1);       // ]0, Map_Count - 1]
-               insertpos = ceil(insertpos) + 1;               // {2, 3, 4, ..., Map_Count}
-               LOG_TRACE("SHUFFLE: insert pos = ", ftos(insertpos));
-
-               // insert the current map there
-               newlist = "";
-               for(j = 1; j < insertpos; ++j)                 // i == 1: no loop, will be inserted as first; however, i == 1 has been excluded above
-                       newlist = strcat(newlist, " ", argv(j));
-               newlist = strcat(newlist, " ", argv(0));       // now insert the just selected map
-               for(j = insertpos; j < Map_Count; ++j)         // i == Map_Count: no loop, has just been inserted as last
-                       newlist = strcat(newlist, " ", argv(j));
-               newlist = substring(newlist, 1, strlen(newlist) - 1);
-               cvar_set("g_maplist", newlist);
-               Map_Count = tokenizebyseparator(autocvar_g_maplist, " ");
-
-               // NOTE: the selected map has just been inserted at (insertpos-1)th position
-               Map_Current = insertpos - 1; // this is not really valid, but this way the fallback has a chance of working
-               if(Map_Check(Map_Current, 1))
-                       return Map_Current;
-       }
-       return -1;
-}
-
-void Maplist_Init()
-{
-       float i = Map_Count = 0;
-       if(autocvar_g_maplist != "")
-       {
-               Map_Count = tokenizebyseparator(autocvar_g_maplist, " ");
-               for (i = 0; i < Map_Count; ++i)
-               {
-                       if (Map_Check(i, 2))
-                               break;
-               }
-       }
-
-       if (i == Map_Count)
-       {
-               bprint( "Maplist contains no usable maps!  Resetting it to default map list.\n" );
-               cvar_set("g_maplist", MapInfo_ListAllAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags() | MAPINFO_FLAG_NOAUTOMAPLIST));
-               if(autocvar_g_maplist_shuffle)
-                       ShuffleMaplist();
-               if(!server_is_dedicated)
-                       localcmd("\nmenu_cmd sync\n");
-               Map_Count = tokenizebyseparator(autocvar_g_maplist, " ");
-       }
-       if(Map_Count == 0)
-               error("empty maplist, cannot select a new map");
-       Map_Current = bound(0, GetMaplistPosition(), Map_Count - 1);
-
-       strcpy(Map_Current_Name, argv(Map_Current)); // will be automatically freed on exit thanks to DP
-       // this may or may not be correct, but who cares, in the worst case a map
-       // isn't chosen in the first pass that should have been
-}
-
-string GetNextMap()
-{
-       Maplist_Init();
-       float nextMap = -1;
-
-       if(nextMap == -1)
-               if(autocvar_g_maplist_shuffle > 0)
-                       nextMap = MaplistMethod_Shuffle(autocvar_g_maplist_shuffle + 1);
-
-       if(nextMap == -1)
-               if(autocvar_g_maplist_selectrandom)
-                       nextMap = MaplistMethod_Random();
-
-       if(nextMap == -1)
-               nextMap = MaplistMethod_Iterate();
-
-       if(nextMap == -1)
-               nextMap = MaplistMethod_Repeat();
-
-       if(nextMap >= 0)
-       {
-               Map_Goto_SetFloat(nextMap);
-               return getmapname_stored;
-       }
-
-       return "";
-}
-
-float DoNextMapOverride(float reinit)
-{
-       if(autocvar_g_campaign)
-       {
-               CampaignPostIntermission();
-               alreadychangedlevel = true;
-               return true;
-       }
-       if(autocvar_quit_when_empty)
-       {
-               if(player_count <= currentbots)
-               {
-                       localcmd("quit\n");
-                       alreadychangedlevel = true;
-                       return true;
-               }
-       }
-       if(autocvar_quit_and_redirect != "")
-       {
-               redirection_target = strzone(autocvar_quit_and_redirect);
-               alreadychangedlevel = true;
-               return true;
-       }
-       if (!reinit && autocvar_samelevel) // if samelevel is set, stay on same level
-       {
-               localcmd("restart\n");
-               alreadychangedlevel = true;
-               return true;
-       }
-       if(autocvar_nextmap != "")
-       {
-               string m;
-               m = GameTypeVote_MapInfo_FixName(autocvar_nextmap);
-               cvar_set("nextmap",m);
-
-               if(!m || gametypevote)
-                       return false;
-               if(autocvar_sv_vote_gametype)
-               {
-                       Map_Goto_SetStr(m);
-                       return false;
-               }
-
-               if(MapInfo_CheckMap(m))
-               {
-                       Map_Goto_SetStr(m);
-                       Map_Goto(reinit);
-                       alreadychangedlevel = true;
-                       return true;
-               }
-       }
-       if(!reinit && autocvar_lastlevel)
-       {
-               cvar_settemp_restore();
-               localcmd("set lastlevel 0\ntogglemenu 1\n");
-               alreadychangedlevel = true;
-               return true;
-       }
-       return false;
-}
-
-void GotoNextMap(float reinit)
-{
-       //string nextmap;
-       //float n, nummaps;
-       //string s;
-       if (alreadychangedlevel)
-               return;
-       alreadychangedlevel = true;
-
-       string nextMap = GetNextMap();
-       if(nextMap == "")
-               error("Everything is broken - cannot find a next map. Please report this to the developers.");
-       Map_Goto(reinit);
-}
-
-
-/*
-============
-IntermissionThink
-
-When the player presses attack or jump, change to the next level
-============
-*/
-.float autoscreenshot;
-void IntermissionThink(entity this)
-{
-       FixIntermissionClient(this);
-
-       float server_screenshot = (autocvar_sv_autoscreenshot && CS(this).cvar_cl_autoscreenshot);
-       float client_screenshot = (CS(this).cvar_cl_autoscreenshot == 2);
-
-       if( (server_screenshot || client_screenshot)
-               && ((this.autoscreenshot > 0) && (time > this.autoscreenshot)) )
-       {
-               this.autoscreenshot = -1;
-               if(IS_REAL_CLIENT(this)) { stuffcmd(this, sprintf("\nscreenshot screenshots/autoscreenshot/%s-%s.jpg; echo \"^5A screenshot has been taken at request of the server.\"\n", GetMapname(), strftime(false, "%s"))); }
-               return;
-       }
-
-       if (time < intermission_exittime)
-               return;
-
-       if(!mapvote_initialized)
-               if (time < intermission_exittime + 10 && !(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this) || PHYS_INPUT_BUTTON_ATCK2(this) || PHYS_INPUT_BUTTON_HOOK(this) || PHYS_INPUT_BUTTON_USE(this)))
-                       return;
-
-       MapVote_Start();
-}
-
-/*
-===============================================================================
-
-RULES
-
-===============================================================================
-*/
-
-void DumpStats(float final)
-{
-       float file;
-       string s;
-       float to_console;
-       float to_eventlog;
-       float to_file;
-       float i;
-
-       to_console = autocvar_sv_logscores_console;
-       to_eventlog = autocvar_sv_eventlog;
-       to_file = autocvar_sv_logscores_file;
-
-       if(!final)
-       {
-               to_console = true; // always print printstats replies
-               to_eventlog = false; // but never print them to the event log
-       }
-
-       if(to_eventlog)
-               if(autocvar_sv_eventlog_console)
-                       to_console = false; // otherwise we get the output twice
-
-       if(final)
-               s = ":scores:";
-       else
-               s = ":status:";
-       s = strcat(s, GetGametype(), "_", GetMapname(), ":", ftos(rint(time)));
-
-       if(to_console)
-               LOG_INFO(s);
-       if(to_eventlog)
-               GameLogEcho(s);
-
-       file = -1;
-       if(to_file)
-       {
-               file = fopen(autocvar_sv_logscores_filename, FILE_APPEND);
-               if(file == -1)
-                       to_file = false;
-               else
-                       fputs(file, strcat(s, "\n"));
-       }
-
-       s = strcat(":labels:player:", GetPlayerScoreString(NULL, 0));
-       if(to_console)
-               LOG_INFO(s);
-       if(to_eventlog)
-               GameLogEcho(s);
-       if(to_file)
-               fputs(file, strcat(s, "\n"));
-
-       FOREACH_CLIENT(IS_REAL_CLIENT(it) || (IS_BOT_CLIENT(it) && autocvar_sv_logscores_bots), {
-               s = strcat(":player:see-labels:", GetPlayerScoreString(it, 0), ":");
-               s = strcat(s, ftos(rint(time - CS(it).jointime)), ":");
-               if(IS_PLAYER(it) || MUTATOR_CALLHOOK(GetPlayerStatus, it))
-                       s = strcat(s, ftos(it.team), ":");
-               else
-                       s = strcat(s, "spectator:");
-
-               if(to_console)
-                       LOG_INFO(s, playername(it, false));
-               if(to_eventlog)
-                       GameLogEcho(strcat(s, ftos(it.playerid), ":", playername(it, false)));
-               if(to_file)
-                       fputs(file, strcat(s, playername(it, false), "\n"));
-       });
-
-       if(teamplay)
-       {
-               s = strcat(":labels:teamscores:", GetTeamScoreString(0, 0));
-               if(to_console)
-                       LOG_INFO(s);
-               if(to_eventlog)
-                       GameLogEcho(s);
-               if(to_file)
-                       fputs(file, strcat(s, "\n"));
-
-               for(i = 1; i < 16; ++i)
-               {
-                       s = strcat(":teamscores:see-labels:", GetTeamScoreString(i, 0));
-                       s = strcat(s, ":", ftos(i));
-                       if(to_console)
-                               LOG_INFO(s);
-                       if(to_eventlog)
-                               GameLogEcho(s);
-                       if(to_file)
-                               fputs(file, strcat(s, "\n"));
-               }
-       }
-
-       if(to_console)
-               LOG_INFO(":end");
-       if(to_eventlog)
-               GameLogEcho(":end");
-       if(to_file)
-       {
-               fputs(file, ":end\n");
-               fclose(file);
-       }
-}
-
-void FixIntermissionClient(entity e)
-{
-       if(!e.autoscreenshot) // initial call
-       {
-               e.autoscreenshot = time + 0.8;  // used for autoscreenshot
-               SetResourceExplicit(e, RES_HEALTH, -2342);
-               // first intermission phase; voting phase has positive health (used to decide whether to send SVC_FINALE or not)
-               for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-               {
-                   .entity weaponentity = weaponentities[slot];
-                       if(e.(weaponentity))
-                       {
-                               e.(weaponentity).effects = EF_NODRAW;
-                               if (e.(weaponentity).weaponchild)
-                                       e.(weaponentity).weaponchild.effects = EF_NODRAW;
-                       }
-               }
-               if(IS_REAL_CLIENT(e))
-               {
-                       stuffcmd(e, "\nscr_printspeed 1000000\n");
-                       RandomSelection_Init();
-                       FOREACH_WORD(autocvar_sv_intermission_cdtrack, true, {
-                               RandomSelection_AddString(it, 1, 1);
-                       });
-                       if (RandomSelection_chosen_string != "")
-                       {
-                               stuffcmd(e, sprintf("\ncd loop %s\n", RandomSelection_chosen_string));
-                       }
-                       msg_entity = e;
-                       WriteByte(MSG_ONE, SVC_INTERMISSION);
-               }
-       }
-}
-
-/*
-go to the next level for deathmatch
-only called if a time or frag limit has expired
-*/
-void NextLevel()
-{
-       game_stopped = true;
-       intermission_running = 1; // game over
-
-       // enforce a wait time before allowing changelevel
-       if(player_count > 0)
-               intermission_exittime = time + autocvar_sv_mapchange_delay;
-       else
-               intermission_exittime = -1;
-
-       /*
-       WriteByte (MSG_ALL, SVC_CDTRACK);
-       WriteByte (MSG_ALL, 3);
-       WriteByte (MSG_ALL, 3);
-       // done in FixIntermission
-       */
-
-       //pos = FindIntermission ();
-
-       VoteReset();
-
-       DumpStats(true);
-
-       // send statistics
-       PlayerStats_GameReport(true);
-       WeaponStats_Shutdown();
-
-       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_Null); // kill all centerprints now
-
-       if(autocvar_sv_eventlog)
-               GameLogEcho(":gameover");
-
-       GameLogClose();
-
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               FixIntermissionClient(it);
-               if(it.winning)
-                       bprint(playername(it, false), " ^7wins.\n");
-       });
-
-       target_music_kill();
-
-       if(autocvar_g_campaign)
-               CampaignPreIntermission();
-
-       MUTATOR_CALLHOOK(MatchEnd);
-
-       localcmd("\nsv_hook_gameend\n");
-}
-
-
-float InitiateSuddenDeath()
-{
-       // Check first whether normal overtimes could be added before initiating suddendeath mode
-       // - for this timelimit_overtime needs to be >0 of course
-       // - also check the winning condition calculated in the previous frame and only add normal overtime
-       //   again, if at the point at which timelimit would be extended again, still no winner was found
-       if (!autocvar_g_campaign && checkrules_overtimesadded >= 0
-               && (checkrules_overtimesadded < autocvar_timelimit_overtimes || autocvar_timelimit_overtimes < 0)
-               && autocvar_timelimit_overtime && !(g_race && !g_race_qualifying))
-       {
-               return 1; // need to call InitiateOvertime later
-       }
-       else
-       {
-               if(!checkrules_suddendeathend)
-               {
-                       if(autocvar_g_campaign)
-                               checkrules_suddendeathend = time; // no suddendeath in campaign
-                       else
-                               checkrules_suddendeathend = time + 60 * autocvar_timelimit_suddendeath;
-                       if(g_race && !g_race_qualifying)
-                               race_StartCompleting();
-               }
-               return 0;
-       }
-}
-
-void InitiateOvertime() // ONLY call this if InitiateSuddenDeath returned true
-{
-       ++checkrules_overtimesadded;
-       //add one more overtime by simply extending the timelimit
-       cvar_set("timelimit", ftos(autocvar_timelimit + autocvar_timelimit_overtime));
-       Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime * 60);
-}
-
-float GetWinningCode(float fraglimitreached, float equality)
-{
-       if(autocvar_g_campaign == 1)
-       {
-               if(fraglimitreached)
-                       return WINNING_YES;
-               else
-                       return WINNING_NO;
-       }
-       else
-       {
-               if(equality)
-               {
-                       if(fraglimitreached)
-                               return WINNING_STARTSUDDENDEATHOVERTIME;
-                       else
-                               return WINNING_NEVER;
-               }
-               else
-               {
-                       if(fraglimitreached)
-                               return WINNING_YES;
-                       else
-                               return WINNING_NO;
-               }
-       }
-}
-
-// set the .winning flag for exactly those players with a given field value
-void SetWinners(.float field, float value)
-{
-       FOREACH_CLIENT(IS_PLAYER(it), { it.winning = (it.(field) == value); });
-}
-
-// set the .winning flag for those players with a given field value
-void AddWinners(.float field, float value)
-{
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               if(it.(field) == value)
-                       it.winning = 1;
-       });
-}
-
-// clear the .winning flags
-void ClearWinners()
-{
-       FOREACH_CLIENT(IS_PLAYER(it), { it.winning = 0; });
-}
-
-void ShuffleMaplist()
-{
-       cvar_set("g_maplist", shufflewords(autocvar_g_maplist));
-}
-
-int fragsleft_last;
-float WinningCondition_Scores(float limit, float leadlimit)
-{
-       // TODO make everything use THIS winning condition (except LMS)
-       WinningConditionHelper(NULL);
-
-       if(teamplay)
-       {
-               for (int i = 1; i < 5; ++i)
-               {
-                       Team_SetTeamScore(Team_GetTeamFromIndex(i),
-                               TeamScore_GetCompareValue(Team_IndexToTeam(i)));
-               }
-       }
-
-       ClearWinners();
-       if(WinningConditionHelper_winner)
-               WinningConditionHelper_winner.winning = 1;
-       if(WinningConditionHelper_winnerteam >= 0)
-               SetWinners(team, WinningConditionHelper_winnerteam);
-
-       if(WinningConditionHelper_lowerisbetter)
-       {
-               WinningConditionHelper_topscore = -WinningConditionHelper_topscore;
-               WinningConditionHelper_secondscore = -WinningConditionHelper_secondscore;
-               limit = -limit;
-       }
-
-       if(WinningConditionHelper_zeroisworst)
-               leadlimit = 0; // not supported in this mode
-
-       if(MUTATOR_CALLHOOK(Scores_CountFragsRemaining))
-       {
-               float fragsleft;
-               if (checkrules_suddendeathend && time >= checkrules_suddendeathend)
-               {
-                       fragsleft = 1;
-               }
-               else
-               {
-                       fragsleft = FLOAT_MAX;
-                       float leadingfragsleft = FLOAT_MAX;
-                       if (limit)
-                               fragsleft = limit - WinningConditionHelper_topscore;
-                       if (leadlimit)
-                               leadingfragsleft = WinningConditionHelper_secondscore + leadlimit - WinningConditionHelper_topscore;
-
-                       if (limit && leadlimit && autocvar_leadlimit_and_fraglimit)
-                               fragsleft = max(fragsleft, leadingfragsleft);
-                       else
-                               fragsleft = min(fragsleft, leadingfragsleft);
-               }
-
-               if (fragsleft_last != fragsleft) // do not announce same remaining frags multiple times
-               {
-                       if (fragsleft == 1)
-                               Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_REMAINING_FRAG_1);
-                       else if (fragsleft == 2)
-                               Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_REMAINING_FRAG_2);
-                       else if (fragsleft == 3)
-                               Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_REMAINING_FRAG_3);
-
-                       fragsleft_last = fragsleft;
-               }
-       }
-
-       bool fraglimit_reached = (limit && WinningConditionHelper_topscore >= limit);
-       bool leadlimit_reached = (leadlimit && WinningConditionHelper_topscore - WinningConditionHelper_secondscore >= leadlimit);
-
-       bool limit_reached;
-       // only respect leadlimit_and_fraglimit when both limits are set or the game will never end
-       if (limit && leadlimit && autocvar_leadlimit_and_fraglimit)
-               limit_reached = (fraglimit_reached && leadlimit_reached);
-       else
-               limit_reached = (fraglimit_reached || leadlimit_reached);
-
-       return GetWinningCode(
-               WinningConditionHelper_topscore && limit_reached,
-               WinningConditionHelper_equality
-       );
-}
-
-float WinningCondition_RanOutOfSpawns()
-{
-       if(have_team_spawns <= 0)
-               return WINNING_NO;
-
-       if(!autocvar_g_spawn_useallspawns)
-               return WINNING_NO;
-
-       if(!some_spawn_has_been_used)
-               return WINNING_NO;
-
-       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))
-               {
-                       Team_SetTeamScore(Team_GetTeam(it.team), 1);
-               }
-       });
-
-       IL_EACH(g_spawnpoints, true,
-       {
-               if (Team_IsValidTeam(it.team))
-               {
-                       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;
-               return WINNING_YES;
-       }
-       else if(team1_score + team2_score + team3_score + team4_score == 1)
-       {
-               float t, i;
-               if(team1_score)
-                       t = 1;
-               else if(team2_score)
-                       t = 2;
-               else if(team3_score)
-                       t = 3;
-               else // if(team4_score)
-                       t = 4;
-               entity balance = TeamBalance_CheckAllowedTeams(NULL);
-               for(i = 0; i < MAX_TEAMSCORE; ++i)
-               {
-                       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);
-               return WINNING_YES;
-       }
-       else
-               return WINNING_NO;
-}
-
-/*
-============
-CheckRules_World
-
-Exit deathmatch games upon conditions
-============
-*/
-void CheckRules_World()
-{
-       VoteThink();
-       MapVote_Think();
-
-       SetDefaultAlpha();
-
-       if (intermission_running) // someone else quit the game already
-       {
-               if(player_count == 0) // Nobody there? Then let's go to the next map
-                       MapVote_Start();
-                       // this will actually check the player count in the next frame
-                       // again, but this shouldn't hurt
-               return;
-       }
-
-       float timelimit = autocvar_timelimit * 60;
-       float fraglimit = autocvar_fraglimit;
-       float leadlimit = autocvar_leadlimit;
-       if (leadlimit < 0) leadlimit = 0;
-
-       if(warmup_stage || time <= game_starttime) // NOTE: this is <= to prevent problems in the very tic where the game starts
-       {
-               if(timelimit > 0)
-                       timelimit = 0; // timelimit is not made for warmup
-               if(fraglimit > 0)
-                       fraglimit = 0; // no fraglimit for now
-               leadlimit = 0; // no leadlimit for now
-       }
-
-       if(timelimit > 0)
-       {
-               timelimit += game_starttime;
-       }
-       else if (timelimit < 0)
-       {
-               // endmatch
-               NextLevel();
-               return;
-       }
-
-       float wantovertime;
-       wantovertime = 0;
-
-       if(checkrules_suddendeathend)
-       {
-               if(!checkrules_suddendeathwarning)
-               {
-                       checkrules_suddendeathwarning = true;
-                       if(g_race && !g_race_qualifying)
-                               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_RACE_FINISHLAP);
-                       else
-                               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_FRAG);
-               }
-       }
-       else
-       {
-               if (timelimit && time >= timelimit)
-               {
-                       if(g_race && (g_race_qualifying == 2) && timelimit > 0)
-                       {
-                               float totalplayers;
-                               float playerswithlaps;
-                               float readyplayers;
-                               totalplayers = playerswithlaps = readyplayers = 0;
-                               FOREACH_CLIENT(IS_PLAYER(it), {
-                                       ++totalplayers;
-                                       if(GameRules_scoring_add(it, RACE_FASTEST, 0))
-                                               ++playerswithlaps;
-                                       if(it.ready)
-                                               ++readyplayers;
-                               });
-
-                               // at least 2 of the players have completed a lap: start the RACE
-                               // otherwise, the players should end the qualifying on their own
-                               if(readyplayers || playerswithlaps >= 2)
-                               {
-                                       checkrules_suddendeathend = 0;
-                                       ReadyRestart(); // go to race
-                                       return;
-                               }
-                               else
-                                       wantovertime |= InitiateSuddenDeath();
-                       }
-                       else
-                               wantovertime |= InitiateSuddenDeath();
-               }
-       }
-
-       if (checkrules_suddendeathend && time >= checkrules_suddendeathend)
-       {
-               NextLevel();
-               return;
-       }
-
-       int checkrules_status = WinningCondition_RanOutOfSpawns();
-       if(checkrules_status == WINNING_YES)
-               bprint("Hey! Someone ran out of spawns!\n");
-       else if(MUTATOR_CALLHOOK(CheckRules_World, checkrules_status, timelimit, fraglimit))
-               checkrules_status = M_ARGV(0, float);
-       else
-               checkrules_status = WinningCondition_Scores(fraglimit, leadlimit);
-
-       if(checkrules_status == WINNING_STARTSUDDENDEATHOVERTIME)
-       {
-               checkrules_status = WINNING_NEVER;
-               checkrules_overtimesadded = -1;
-               wantovertime |= InitiateSuddenDeath();
-       }
-
-       if(checkrules_status == WINNING_NEVER)
-               // equality cases! Nobody wins if the overtime ends in a draw.
-               ClearWinners();
-
-       if(wantovertime)
-       {
-               if(checkrules_status == WINNING_NEVER)
-                       InitiateOvertime();
-               else
-                       checkrules_status = WINNING_YES;
-       }
-
-       if(checkrules_suddendeathend)
-               if(checkrules_status != WINNING_NEVER || time >= checkrules_suddendeathend)
-                       checkrules_status = WINNING_YES;
-
-       if(checkrules_status == WINNING_YES)
-       {
-               //print("WINNING\n");
-               NextLevel();
-       }
-}
-
-string GotoMap(string m)
-{
-       m = GameTypeVote_MapInfo_FixName(m);
-       if (!m)
-               return "The map you suggested is not available on this server.";
-       if (!autocvar_sv_vote_gametype)
-       if(!MapInfo_CheckMap(m))
-               return "The map you suggested does not support the current game mode.";
-       cvar_set("nextmap", m);
-       cvar_set("timelimit", "-1");
-       if(mapvote_initialized || alreadychangedlevel)
-       {
-               if(DoNextMapOverride(0))
-                       return "Map switch initiated.";
-               else
-                       return "Hm... no. For some reason I like THIS map more.";
-       }
-       else
-               return "Map switch will happen after scoreboard.";
-}
-
-bool autocvar_sv_gameplayfix_multiplethinksperframe = true;
-void RunThink(entity this)
-{
-       // don't let things stay in the past.
-       // it is possible to start that way by a trigger with a local time.
-       if(this.nextthink <= 0 || this.nextthink > time + frametime)
-               return;
-
-       float oldtime = time; // do we need to save this?
-
-       for (int iterations = 0; iterations < 128 && !wasfreed(this); iterations++)
-       {
-               time = max(oldtime, this.nextthink);
-               this.nextthink = 0;
-
-               if(getthink(this))
-                       getthink(this)(this);
-               // mods often set nextthink to time to cause a think every frame,
-               // we don't want to loop in that case, so exit if the new nextthink is
-               // <= the time the qc was told, also exit if it is past the end of the
-               // frame
-               if(this.nextthink <= time || this.nextthink > oldtime + frametime || !autocvar_sv_gameplayfix_multiplethinksperframe)
-                       break;
-       }
-
-       time = oldtime;
-}
-
-bool autocvar_sv_freezenonclients;
-bool autocvar_sv_gameplayfix_delayprojectiles = false;
-void Physics_Frame()
-{
-       if(autocvar_sv_freezenonclients)
-               return;
-
-       IL_EACH(g_moveables, true,
-       {
-               if(IS_CLIENT(it) || it.classname == "" || it.move_movetype == MOVETYPE_PHYSICS)
-                       continue;
-
-               //set_movetype(it, it.move_movetype);
-               // inline the set_movetype function, since this is called a lot
-               it.movetype = (it.move_qcphysics) ? MOVETYPE_QCENTITY : it.move_movetype;
-
-               if(it.move_qcphysics && it.move_movetype != MOVETYPE_NONE)
-                       Movetype_Physics_NoMatchTicrate(it, PHYS_INPUT_TIMELENGTH, false);
-
-               if(it.movetype >= MOVETYPE_USER_FIRST && it.movetype <= MOVETYPE_USER_LAST) // these cases have no think handling
-               {
-                       if(it.move_movetype == MOVETYPE_PUSH || it.move_movetype == MOVETYPE_FAKEPUSH)
-                               continue; // these movetypes have no regular think function
-                       // handle thinking here
-                       if (getthink(it) && it.nextthink > 0 && it.nextthink <= time + frametime)
-                               RunThink(it);
-               }
-       });
-
-       if(autocvar_sv_gameplayfix_delayprojectiles >= 0)
-               return;
-
-       IL_EACH(g_moveables, it.move_qcphysics,
-       {
-               if(IS_CLIENT(it) || it.classname == "" || it.move_movetype == MOVETYPE_NONE)
-                       continue;
-               Movetype_Physics_NoMatchTicrate(it, PHYS_INPUT_TIMELENGTH, false);
-       });
-}
-
-void systems_update();
-void EndFrame()
-{
-       anticheat_endframe();
-
-       Physics_Frame();
-
-       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
-               entity e = IS_SPEC(it) ? it.enemy : it;
-               if (e.typehitsound) {
-                       STAT(TYPEHIT_TIME, it) = time;
-               } else if (e.killsound) {
-                       STAT(KILL_TIME, it) = time;
-               } else if (e.damage_dealt) {
-                       STAT(HIT_TIME, it) = time;
-                       STAT(DAMAGE_DEALT_TOTAL, it) += ceil(e.damage_dealt);
-               }
-       });
-       // add 1 frametime because after this, engine SV_Physics
-       // increases time by a frametime and then networks the frame
-       // add another frametime because client shows everything with
-       // 1 frame of lag (cl_nolerp 0). The last +1 however should not be
-       // needed!
-       float altime = time + frametime * (1 + autocvar_g_antilag_nudge);
-       FOREACH_CLIENT(true, {
-               it.typehitsound = false;
-               it.damage_dealt = 0;
-               it.killsound = false;
-               antilag_record(it, CS(it), altime);
-       });
-       IL_EACH(g_monsters, true,
-       {
-               antilag_record(it, it, altime);
-       });
-       IL_EACH(g_projectiles, it.classname == "nade",
-       {
-               antilag_record(it, it, altime);
-       });
-       systems_update();
-       IL_ENDFRAME();
-}
-
-
-/*
- * RedirectionThink:
- * returns true if redirecting
- */
-float redirection_timeout;
-float redirection_nextthink;
-float RedirectionThink()
-{
-       float clients_found;
-
-       if(redirection_target == "")
-               return false;
-
-       if(!redirection_timeout)
-       {
-               cvar_set("sv_public", "-2");
-               redirection_timeout = time + 0.6; // this will only try twice... should be able to keep more clients
-               if(redirection_target == "self")
-                       bprint("^3SERVER NOTICE:^7 restarting the server\n");
-               else
-                       bprint("^3SERVER NOTICE:^7 redirecting everyone to ", redirection_target, "\n");
-       }
-
-       if(time < redirection_nextthink)
-               return true;
-
-       redirection_nextthink = time + 1;
-
-       clients_found = 0;
-       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
-               // TODO add timer
-               LOG_INFO("Redirecting: sending connect command to ", it.netname);
-               if(redirection_target == "self")
-                       stuffcmd(it, "\ndisconnect; defer ", ftos(autocvar_quit_and_redirect_timer), " reconnect\n");
-               else
-                       stuffcmd(it, strcat("\ndisconnect; defer ", ftos(autocvar_quit_and_redirect_timer), " \"connect ", redirection_target, "\"\n"));
-               ++clients_found;
-       });
-
-       LOG_INFO("Redirecting: ", ftos(clients_found), " clients left.");
-
-       if(time > redirection_timeout || clients_found == 0)
-               localcmd("\nwait; wait; wait; quit\n");
-
-       return true;
-}
-
-void RestoreGame()
-{
-       // Loaded from a save game
-       // some things then break, so let's work around them...
-
-       // Progs DB (capture records)
-       ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid));
-
-       // Mapinfo
-       MapInfo_Shutdown();
-       MapInfo_Enumerate();
-       MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1);
-       WeaponStats_Init();
-
-       TargetMusic_RestoreGame();
-}
-
-void Shutdown()
-{
-       game_stopped = 2;
-
-       if(world_initialized > 0)
-       {
-               world_initialized = 0;
-
-               // if a timeout is active, reset the slowmo value to normal
-               if(timeout_status == TIMEOUT_ACTIVE)
-                       cvar_set("slowmo", ftos(orig_slowmo));
-
-               LOG_TRACE("Saving persistent data...");
-               Ban_SaveBans();
-
-               // playerstats with unfinished match
-               PlayerStats_GameReport(false);
-
-               if(!cheatcount_total)
-               {
-                       if(autocvar_sv_db_saveasdump)
-                               db_dump(ServerProgsDB, strcat("server.db", autocvar_sessionid));
-                       else
-                               db_save(ServerProgsDB, strcat("server.db", autocvar_sessionid));
-               }
-               if(autocvar_developer > 0)
-               {
-                       if(autocvar_sv_db_saveasdump)
-                               db_dump(TemporaryDB, "server-temp.db");
-                       else
-                               db_save(TemporaryDB, "server-temp.db");
-               }
-               CheatShutdown(); // must be after cheatcount check
-               db_close(ServerProgsDB);
-               db_close(TemporaryDB);
-               LOG_TRACE("Saving persistent data... done!");
-               // tell the bot system the game is ending now
-               bot_endgame();
-
-               WeaponStats_Shutdown();
-               MapInfo_Shutdown();
-       }
-       else if(world_initialized == 0)