]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'DefaultUser/gametype_votescreen' into 'master'
authorMario <zacjardine@y7mail.com>
Thu, 1 Sep 2016 11:10:05 +0000 (11:10 +0000)
committerMario <zacjardine@y7mail.com>
Thu, 1 Sep 2016 11:10:05 +0000 (11:10 +0000)
Gametype Votescreen: Fix icons for custom gamemodes and add option for custom icons

See merge request !359

806 files changed:
.gitlab-ci.yml
CMakeLists.txt
defaultXonotic.cfg
gamemodes.cfg
models/player/megaerebus.iqm_0.txt
models/player/pyria.iqm_0.skin
models/player/pyria_lod1.iqm_0.skin
models/player/pyria_lod2.iqm_0.skin
models/player/seraphinamasked.iqm_0.skin
models/player/seraphinamasked_lod1.iqm_0.skin
models/player/seraphinamasked_lod2.iqm_0.skin
monsters.cfg
qcsrc/Doxyfile
qcsrc/Makefile
qcsrc/client/_all.inc [new file with mode: 0644]
qcsrc/client/_all.qh
qcsrc/client/autocvars.qh
qcsrc/client/commands/_mod.inc
qcsrc/client/commands/_mod.qh
qcsrc/client/commands/all.qc [deleted file]
qcsrc/client/commands/all.qh [deleted file]
qcsrc/client/commands/cl_cmd.qc
qcsrc/client/csqcmodel_hooks.qc
qcsrc/client/defs.qh
qcsrc/client/hud/_mod.inc
qcsrc/client/hud/_mod.qh
qcsrc/client/hud/all.inc [deleted file]
qcsrc/client/hud/all.qh [deleted file]
qcsrc/client/hud/hud.qc
qcsrc/client/hud/hud.qh
qcsrc/client/hud/hud_config.qc
qcsrc/client/hud/panel.qc [new file with mode: 0644]
qcsrc/client/hud/panel/_mod.inc
qcsrc/client/hud/panel/_mod.qh
qcsrc/client/hud/panel/ammo.qc
qcsrc/client/hud/panel/ammo.qh
qcsrc/client/hud/panel/centerprint.qc
qcsrc/client/hud/panel/centerprint.qh
qcsrc/client/hud/panel/chat.qc
qcsrc/client/hud/panel/engineinfo.qc
qcsrc/client/hud/panel/healtharmor.qc
qcsrc/client/hud/panel/infomessages.qc
qcsrc/client/hud/panel/minigame.qc
qcsrc/client/hud/panel/modicons.qc
qcsrc/client/hud/panel/notify.qc
qcsrc/client/hud/panel/physics.qc
qcsrc/client/hud/panel/powerups.qc
qcsrc/client/hud/panel/powerups.qh
qcsrc/client/hud/panel/pressedkeys.qc
qcsrc/client/hud/panel/quickmenu.qc
qcsrc/client/hud/panel/racetimer.qc
qcsrc/client/hud/panel/radar.qc
qcsrc/client/hud/panel/score.qc
qcsrc/client/hud/panel/scoreboard.qc
qcsrc/client/hud/panel/timer.qc
qcsrc/client/hud/panel/vote.qc
qcsrc/client/hud/panel/weapons.qc
qcsrc/client/main.qc
qcsrc/client/main.qh
qcsrc/client/mapvoting.qc
qcsrc/client/miscfunctions.qc
qcsrc/client/miscfunctions.qh
qcsrc/client/mutators/_mod.inc
qcsrc/client/mutators/_mod.qh
qcsrc/client/mutators/events.qc [new file with mode: 0644]
qcsrc/client/progs.inc
qcsrc/client/shownames.qc
qcsrc/client/teamradar.qc
qcsrc/client/view.qc
qcsrc/common/_all.inc
qcsrc/common/animdecide.qc
qcsrc/common/campaign_file.qc
qcsrc/common/campaign_file.qh [new file with mode: 0644]
qcsrc/common/campaign_setup.qc
qcsrc/common/campaign_setup.qh [new file with mode: 0644]
qcsrc/common/command/_mod.inc
qcsrc/common/command/_mod.qh
qcsrc/common/command/all.qc [deleted file]
qcsrc/common/command/all.qh [deleted file]
qcsrc/common/command/generic.qc
qcsrc/common/command/markup.qc
qcsrc/common/command/reg.qc [new file with mode: 0644]
qcsrc/common/command/reg.qh [new file with mode: 0644]
qcsrc/common/command/rpn.qc
qcsrc/common/constants.qh
qcsrc/common/debug.qh
qcsrc/common/effects/_mod.inc
qcsrc/common/effects/_mod.qh
qcsrc/common/effects/effectinfo.qc
qcsrc/common/effects/effectinfo.qh [new file with mode: 0644]
qcsrc/common/effects/qc/casings.qc
qcsrc/common/effects/qc/casings.qh [new file with mode: 0644]
qcsrc/common/effects/qc/damageeffects.qc
qcsrc/common/effects/qc/damageeffects.qh [new file with mode: 0644]
qcsrc/common/effects/qc/globalsound.qc
qcsrc/common/effects/qc/rubble.qh
qcsrc/common/ent_cs.qc
qcsrc/common/ent_cs.qh
qcsrc/common/gamemodes/_mod.inc
qcsrc/common/gamemodes/_mod.qh
qcsrc/common/gamemodes/all.inc [deleted file]
qcsrc/common/gamemodes/all.qc [deleted file]
qcsrc/common/gamemodes/all.qh [deleted file]
qcsrc/common/gamemodes/gamemode/_mod.inc
qcsrc/common/gamemodes/gamemode/_mod.qh
qcsrc/common/gamemodes/gamemode/nexball/module.inc [deleted file]
qcsrc/common/gamemodes/gamemode/nexball/nexball.qc
qcsrc/common/gamemodes/gamemode/nexball/nexball.qh
qcsrc/common/gamemodes/gamemode/nexball/weapon.qc
qcsrc/common/gamemodes/gamemode/nexball/weapon.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/_mod.inc
qcsrc/common/gamemodes/gamemode/onslaught/_mod.qh
qcsrc/common/gamemodes/gamemode/onslaught/cl_controlpoint.qc
qcsrc/common/gamemodes/gamemode/onslaught/cl_controlpoint.qh
qcsrc/common/gamemodes/gamemode/onslaught/cl_generator.qc
qcsrc/common/gamemodes/gamemode/onslaught/cl_generator.qh
qcsrc/common/gamemodes/gamemode/onslaught/controlpoint.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/controlpoint.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/generator.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/generator.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/module.inc [deleted file]
qcsrc/common/gamemodes/gamemode/onslaught/onslaught.qc
qcsrc/common/gamemodes/gamemode/onslaught/onslaught.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/sv_controlpoint.qh
qcsrc/common/gamemodes/gamemode/onslaught/sv_generator.qh
qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qh [new file with mode: 0644]
qcsrc/common/items/_mod.inc
qcsrc/common/items/_mod.qh
qcsrc/common/items/all.qc
qcsrc/common/items/all.qh
qcsrc/common/items/item/ammo.qc
qcsrc/common/items/item/ammo.qh
qcsrc/common/items/item/armor.qc
qcsrc/common/items/item/armor.qh
qcsrc/common/items/item/health.qc
qcsrc/common/items/item/health.qh
qcsrc/common/items/item/jetpack.qc
qcsrc/common/items/item/jetpack.qh [new file with mode: 0644]
qcsrc/common/items/item/pickup.qh
qcsrc/common/items/item/powerup.qc
qcsrc/common/items/item/powerup.qh
qcsrc/common/mapinfo.qc
qcsrc/common/mapinfo.qh
qcsrc/common/minigames/_mod.inc
qcsrc/common/minigames/_mod.qh
qcsrc/common/minigames/cl_minigames_hud.qc
qcsrc/common/minigames/minigame/bd.qc
qcsrc/common/minigames/minigame/bd.qh [new file with mode: 0644]
qcsrc/common/minigames/minigame/c4.qc
qcsrc/common/minigames/minigame/c4.qh [new file with mode: 0644]
qcsrc/common/minigames/minigame/nmm.qc
qcsrc/common/minigames/minigame/nmm.qh [new file with mode: 0644]
qcsrc/common/minigames/minigame/pong.qc
qcsrc/common/minigames/minigame/pong.qh [new file with mode: 0644]
qcsrc/common/minigames/minigame/pp.qc
qcsrc/common/minigames/minigame/pp.qh [new file with mode: 0644]
qcsrc/common/minigames/minigame/ps.qc
qcsrc/common/minigames/minigame/ps.qh [new file with mode: 0644]
qcsrc/common/minigames/minigame/snake.qc
qcsrc/common/minigames/minigame/snake.qh [new file with mode: 0644]
qcsrc/common/minigames/minigame/ttt.qc
qcsrc/common/minigames/minigame/ttt.qh [new file with mode: 0644]
qcsrc/common/minigames/sv_minigames.qc
qcsrc/common/monsters/_mod.inc
qcsrc/common/monsters/_mod.qh
qcsrc/common/monsters/all.qc
qcsrc/common/monsters/all.qh
qcsrc/common/monsters/monster.qh
qcsrc/common/monsters/monster/mage.qc
qcsrc/common/monsters/monster/mage.qh [new file with mode: 0644]
qcsrc/common/monsters/monster/shambler.qc
qcsrc/common/monsters/monster/shambler.qh [new file with mode: 0644]
qcsrc/common/monsters/monster/spider.qc
qcsrc/common/monsters/monster/spider.qh [new file with mode: 0644]
qcsrc/common/monsters/monster/wyvern.qc
qcsrc/common/monsters/monster/wyvern.qh [new file with mode: 0644]
qcsrc/common/monsters/monster/zombie.qc
qcsrc/common/monsters/monster/zombie.qh [new file with mode: 0644]
qcsrc/common/monsters/spawn.qc [deleted file]
qcsrc/common/monsters/spawn.qh [deleted file]
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/monsters/sv_spawn.qc [new file with mode: 0644]
qcsrc/common/monsters/sv_spawn.qh [new file with mode: 0644]
qcsrc/common/mutators/_mod.inc
qcsrc/common/mutators/_mod.qh
qcsrc/common/mutators/all.inc [deleted file]
qcsrc/common/mutators/all.qc [deleted file]
qcsrc/common/mutators/all.qh [deleted file]
qcsrc/common/mutators/base.qh
qcsrc/common/mutators/events.qh
qcsrc/common/mutators/mutator/_mod.inc
qcsrc/common/mutators/mutator/_mod.qh
qcsrc/common/mutators/mutator/bloodloss/_mod.inc
qcsrc/common/mutators/mutator/bloodloss/_mod.qh
qcsrc/common/mutators/mutator/bloodloss/bloodloss.qc [deleted file]
qcsrc/common/mutators/mutator/bloodloss/module.inc [deleted file]
qcsrc/common/mutators/mutator/bloodloss/sv_bloodloss.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/bloodloss/sv_bloodloss.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/breakablehook/_mod.inc
qcsrc/common/mutators/mutator/breakablehook/_mod.qh
qcsrc/common/mutators/mutator/breakablehook/breakablehook.qc [deleted file]
qcsrc/common/mutators/mutator/breakablehook/module.inc [deleted file]
qcsrc/common/mutators/mutator/breakablehook/sv_breakablehook.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/breakablehook/sv_breakablehook.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/buffs/_mod.inc
qcsrc/common/mutators/mutator/buffs/_mod.qh
qcsrc/common/mutators/mutator/buffs/all.qc [deleted file]
qcsrc/common/mutators/mutator/buffs/all.qh [deleted file]
qcsrc/common/mutators/mutator/buffs/buffs.qc
qcsrc/common/mutators/mutator/buffs/buffs.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/buffs/cl_buffs.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/buffs/cl_buffs.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/buffs/module.inc [deleted file]
qcsrc/common/mutators/mutator/buffs/sv_buffs.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/buffs/sv_buffs.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/bugrigs/bugrigs.qc
qcsrc/common/mutators/mutator/bugrigs/bugrigs.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/bugrigs/module.inc [deleted file]
qcsrc/common/mutators/mutator/campcheck/_mod.inc
qcsrc/common/mutators/mutator/campcheck/_mod.qh
qcsrc/common/mutators/mutator/campcheck/campcheck.qc
qcsrc/common/mutators/mutator/campcheck/campcheck.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/campcheck/module.inc [deleted file]
qcsrc/common/mutators/mutator/campcheck/sv_campcheck.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/campcheck/sv_campcheck.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/cloaked/_mod.inc
qcsrc/common/mutators/mutator/cloaked/_mod.qh
qcsrc/common/mutators/mutator/cloaked/cloaked.qc [deleted file]
qcsrc/common/mutators/mutator/cloaked/module.inc [deleted file]
qcsrc/common/mutators/mutator/cloaked/sv_cloaked.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/cloaked/sv_cloaked.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/damagetext/damagetext.qc
qcsrc/common/mutators/mutator/damagetext/damagetext.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/damagetext/module.inc [deleted file]
qcsrc/common/mutators/mutator/dodging/_mod.inc
qcsrc/common/mutators/mutator/dodging/_mod.qh
qcsrc/common/mutators/mutator/dodging/dodging.qc [deleted file]
qcsrc/common/mutators/mutator/dodging/module.inc [deleted file]
qcsrc/common/mutators/mutator/dodging/sv_dodging.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/dodging/sv_dodging.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/doublejump/doublejump.qc
qcsrc/common/mutators/mutator/doublejump/doublejump.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/doublejump/module.inc [deleted file]
qcsrc/common/mutators/mutator/globalforces/_mod.inc
qcsrc/common/mutators/mutator/globalforces/_mod.qh
qcsrc/common/mutators/mutator/globalforces/globalforces.qc [deleted file]
qcsrc/common/mutators/mutator/globalforces/module.inc [deleted file]
qcsrc/common/mutators/mutator/globalforces/sv_globalforces.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/globalforces/sv_globalforces.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/hook/_mod.inc
qcsrc/common/mutators/mutator/hook/_mod.qh
qcsrc/common/mutators/mutator/hook/hook.qc [deleted file]
qcsrc/common/mutators/mutator/hook/module.inc [deleted file]
qcsrc/common/mutators/mutator/hook/sv_hook.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/hook/sv_hook.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/instagib/_mod.inc
qcsrc/common/mutators/mutator/instagib/_mod.qh
qcsrc/common/mutators/mutator/instagib/instagib.qc [deleted file]
qcsrc/common/mutators/mutator/instagib/items.qc
qcsrc/common/mutators/mutator/instagib/items.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/instagib/module.inc [deleted file]
qcsrc/common/mutators/mutator/instagib/sv_instagib.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/instagib/sv_instagib.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/invincibleproj/_mod.inc
qcsrc/common/mutators/mutator/invincibleproj/_mod.qh
qcsrc/common/mutators/mutator/invincibleproj/invincibleproj.qc [deleted file]
qcsrc/common/mutators/mutator/invincibleproj/module.inc [deleted file]
qcsrc/common/mutators/mutator/invincibleproj/sv_invincibleproj.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/invincibleproj/sv_invincibleproj.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/itemstime.qc [deleted file]
qcsrc/common/mutators/mutator/itemstime/_mod.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/itemstime/_mod.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/itemstime/itemstime.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/itemstime/itemstime.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/melee_only/_mod.inc
qcsrc/common/mutators/mutator/melee_only/_mod.qh
qcsrc/common/mutators/mutator/melee_only/melee_only.qc [deleted file]
qcsrc/common/mutators/mutator/melee_only/module.inc [deleted file]
qcsrc/common/mutators/mutator/melee_only/sv_melee_only.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/melee_only/sv_melee_only.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/midair/_mod.inc
qcsrc/common/mutators/mutator/midair/_mod.qh
qcsrc/common/mutators/mutator/midair/midair.qc [deleted file]
qcsrc/common/mutators/mutator/midair/module.inc [deleted file]
qcsrc/common/mutators/mutator/midair/sv_midair.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/midair/sv_midair.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/multijump/module.inc [deleted file]
qcsrc/common/mutators/mutator/multijump/multijump.qc
qcsrc/common/mutators/mutator/multijump/multijump.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/nades/module.inc [deleted file]
qcsrc/common/mutators/mutator/nades/nades.inc
qcsrc/common/mutators/mutator/nades/nades.qc
qcsrc/common/mutators/mutator/nades/nades.qh
qcsrc/common/mutators/mutator/nades/net.qc
qcsrc/common/mutators/mutator/nades/net.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/new_toys/_mod.inc
qcsrc/common/mutators/mutator/new_toys/_mod.qh
qcsrc/common/mutators/mutator/new_toys/module.inc [deleted file]
qcsrc/common/mutators/mutator/new_toys/new_toys.qc [deleted file]
qcsrc/common/mutators/mutator/new_toys/sv_new_toys.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/new_toys/sv_new_toys.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/nix/_mod.inc
qcsrc/common/mutators/mutator/nix/_mod.qh
qcsrc/common/mutators/mutator/nix/module.inc [deleted file]
qcsrc/common/mutators/mutator/nix/nix.qc [deleted file]
qcsrc/common/mutators/mutator/nix/sv_nix.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/nix/sv_nix.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/_mod.inc
qcsrc/common/mutators/mutator/overkill/_mod.qh
qcsrc/common/mutators/mutator/overkill/cl_overkill.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/cl_overkill.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/hmg.qc
qcsrc/common/mutators/mutator/overkill/hmg.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/module.inc [deleted file]
qcsrc/common/mutators/mutator/overkill/overkill.qc
qcsrc/common/mutators/mutator/overkill/overkill.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/rpc.qc
qcsrc/common/mutators/mutator/overkill/rpc.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/sv_overkill.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/sv_overkill.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/physical_items/_mod.inc
qcsrc/common/mutators/mutator/physical_items/_mod.qh
qcsrc/common/mutators/mutator/physical_items/module.inc [deleted file]
qcsrc/common/mutators/mutator/physical_items/physical_items.qc [deleted file]
qcsrc/common/mutators/mutator/physical_items/sv_physical_items.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/physical_items/sv_physical_items.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/pinata/_mod.inc
qcsrc/common/mutators/mutator/pinata/_mod.qh
qcsrc/common/mutators/mutator/pinata/module.inc [deleted file]
qcsrc/common/mutators/mutator/pinata/pinata.qc [deleted file]
qcsrc/common/mutators/mutator/pinata/sv_pinata.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/pinata/sv_pinata.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/random_gravity/_mod.inc
qcsrc/common/mutators/mutator/random_gravity/_mod.qh
qcsrc/common/mutators/mutator/random_gravity/module.inc [deleted file]
qcsrc/common/mutators/mutator/random_gravity/random_gravity.qc [deleted file]
qcsrc/common/mutators/mutator/random_gravity/sv_random_gravity.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/random_gravity/sv_random_gravity.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/rocketflying/_mod.inc
qcsrc/common/mutators/mutator/rocketflying/_mod.qh
qcsrc/common/mutators/mutator/rocketflying/module.inc [deleted file]
qcsrc/common/mutators/mutator/rocketflying/rocketflying.qc [deleted file]
qcsrc/common/mutators/mutator/rocketflying/sv_rocketflying.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/rocketflying/sv_rocketflying.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/rocketminsta/_mod.inc
qcsrc/common/mutators/mutator/rocketminsta/_mod.qh
qcsrc/common/mutators/mutator/rocketminsta/module.inc [deleted file]
qcsrc/common/mutators/mutator/rocketminsta/rocketminsta.qc [deleted file]
qcsrc/common/mutators/mutator/rocketminsta/sv_rocketminsta.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/rocketminsta/sv_rocketminsta.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/running_guns/_mod.inc
qcsrc/common/mutators/mutator/running_guns/_mod.qh
qcsrc/common/mutators/mutator/running_guns/module.inc [deleted file]
qcsrc/common/mutators/mutator/running_guns/running_guns.qc [deleted file]
qcsrc/common/mutators/mutator/running_guns/sv_running_guns.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/running_guns/sv_running_guns.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/sandbox/_mod.inc
qcsrc/common/mutators/mutator/sandbox/_mod.qh
qcsrc/common/mutators/mutator/sandbox/module.inc [deleted file]
qcsrc/common/mutators/mutator/sandbox/sandbox.qc [deleted file]
qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/spawn_near_teammate/_mod.inc
qcsrc/common/mutators/mutator/spawn_near_teammate/_mod.qh
qcsrc/common/mutators/mutator/spawn_near_teammate/module.inc [deleted file]
qcsrc/common/mutators/mutator/spawn_near_teammate/spawn_near_teammate.qc [deleted file]
qcsrc/common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/superspec/_mod.inc
qcsrc/common/mutators/mutator/superspec/_mod.qh
qcsrc/common/mutators/mutator/superspec/module.inc [deleted file]
qcsrc/common/mutators/mutator/superspec/superspec.qc [deleted file]
qcsrc/common/mutators/mutator/superspec/sv_superspec.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/superspec/sv_superspec.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/touchexplode/_mod.inc
qcsrc/common/mutators/mutator/touchexplode/_mod.qh
qcsrc/common/mutators/mutator/touchexplode/module.inc [deleted file]
qcsrc/common/mutators/mutator/touchexplode/sv_touchexplode.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/touchexplode/sv_touchexplode.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/touchexplode/touchexplode.qc [deleted file]
qcsrc/common/mutators/mutator/vampire/_mod.inc
qcsrc/common/mutators/mutator/vampire/_mod.qh
qcsrc/common/mutators/mutator/vampire/module.inc [deleted file]
qcsrc/common/mutators/mutator/vampire/sv_vampire.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/vampire/sv_vampire.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/vampire/vampire.qc [deleted file]
qcsrc/common/mutators/mutator/vampirehook/_mod.inc
qcsrc/common/mutators/mutator/vampirehook/_mod.qh
qcsrc/common/mutators/mutator/vampirehook/module.inc [deleted file]
qcsrc/common/mutators/mutator/vampirehook/sv_vampirehook.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/vampirehook/sv_vampirehook.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/vampirehook/vampirehook.qc [deleted file]
qcsrc/common/mutators/mutator/waypoints/all.qh
qcsrc/common/mutators/mutator/waypoints/module.inc [deleted file]
qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc
qcsrc/common/mutators/mutator/waypoints/waypointsprites.qh
qcsrc/common/mutators/mutator/weaponarena_random/_mod.inc
qcsrc/common/mutators/mutator/weaponarena_random/_mod.qh
qcsrc/common/mutators/mutator/weaponarena_random/module.inc [deleted file]
qcsrc/common/mutators/mutator/weaponarena_random/sv_weaponarena_random.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/weaponarena_random/sv_weaponarena_random.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/weaponarena_random/weaponarena_random.qc [deleted file]
qcsrc/common/notifications/all.qc
qcsrc/common/notifications/all.qh
qcsrc/common/physics/_mod.inc
qcsrc/common/physics/_mod.qh
qcsrc/common/physics/movetypes/follow.qc
qcsrc/common/physics/movetypes/follow.qh [new file with mode: 0644]
qcsrc/common/physics/movetypes/movetypes.qc
qcsrc/common/physics/movetypes/step.qc
qcsrc/common/physics/movetypes/step.qh [new file with mode: 0644]
qcsrc/common/physics/movetypes/toss.qc
qcsrc/common/physics/movetypes/toss.qh [new file with mode: 0644]
qcsrc/common/physics/movetypes/walk.qc
qcsrc/common/physics/movetypes/walk.qh [new file with mode: 0644]
qcsrc/common/physics/player.qc
qcsrc/common/playerstats.qc
qcsrc/common/sounds/all.qc
qcsrc/common/stats.qh
qcsrc/common/t_items.qc
qcsrc/common/triggers/_mod.inc
qcsrc/common/triggers/_mod.qh
qcsrc/common/triggers/func/bobbing.qc
qcsrc/common/triggers/func/bobbing.qh [new file with mode: 0644]
qcsrc/common/triggers/func/breakable.qc
qcsrc/common/triggers/func/button.qc
qcsrc/common/triggers/func/button.qh [new file with mode: 0644]
qcsrc/common/triggers/func/conveyor.qc
qcsrc/common/triggers/func/conveyor.qh [new file with mode: 0644]
qcsrc/common/triggers/func/door.qc
qcsrc/common/triggers/func/door_rotating.qc
qcsrc/common/triggers/func/door_rotating.qh [new file with mode: 0644]
qcsrc/common/triggers/func/door_secret.qc
qcsrc/common/triggers/func/door_secret.qh [new file with mode: 0644]
qcsrc/common/triggers/func/fourier.qc
qcsrc/common/triggers/func/fourier.qh [new file with mode: 0644]
qcsrc/common/triggers/func/ladder.qc
qcsrc/common/triggers/func/pendulum.qc
qcsrc/common/triggers/func/pendulum.qh [new file with mode: 0644]
qcsrc/common/triggers/func/plat.qc
qcsrc/common/triggers/func/plat.qh [new file with mode: 0644]
qcsrc/common/triggers/func/pointparticles.qc
qcsrc/common/triggers/func/pointparticles.qh [new file with mode: 0644]
qcsrc/common/triggers/func/rainsnow.qc
qcsrc/common/triggers/func/rainsnow.qh [new file with mode: 0644]
qcsrc/common/triggers/func/rotating.qc
qcsrc/common/triggers/func/rotating.qh [new file with mode: 0644]
qcsrc/common/triggers/func/stardust.qc
qcsrc/common/triggers/func/stardust.qh [new file with mode: 0644]
qcsrc/common/triggers/func/train.qc
qcsrc/common/triggers/func/vectormamamam.qc
qcsrc/common/triggers/func/vectormamamam.qh [new file with mode: 0644]
qcsrc/common/triggers/include.qh
qcsrc/common/triggers/misc/corner.qc
qcsrc/common/triggers/misc/corner.qh [new file with mode: 0644]
qcsrc/common/triggers/misc/follow.qc
qcsrc/common/triggers/misc/follow.qh [new file with mode: 0644]
qcsrc/common/triggers/misc/include.qc
qcsrc/common/triggers/misc/include.qh [new file with mode: 0644]
qcsrc/common/triggers/misc/laser.qc
qcsrc/common/triggers/misc/laser.qh [new file with mode: 0644]
qcsrc/common/triggers/misc/teleport_dest.qc
qcsrc/common/triggers/misc/teleport_dest.qh [new file with mode: 0644]
qcsrc/common/triggers/platforms.qc
qcsrc/common/triggers/subs.qc
qcsrc/common/triggers/target/changelevel.qc
qcsrc/common/triggers/target/changelevel.qh [new file with mode: 0644]
qcsrc/common/triggers/target/location.qc
qcsrc/common/triggers/target/location.qh [new file with mode: 0644]
qcsrc/common/triggers/target/music.qc
qcsrc/common/triggers/target/spawn.qc
qcsrc/common/triggers/target/spawn.qh [new file with mode: 0644]
qcsrc/common/triggers/target/speaker.qc
qcsrc/common/triggers/target/speaker.qh [new file with mode: 0644]
qcsrc/common/triggers/target/voicescript.qc
qcsrc/common/triggers/target/voicescript.qh [new file with mode: 0644]
qcsrc/common/triggers/teleporters.qc
qcsrc/common/triggers/teleporters.qh
qcsrc/common/triggers/trigger/counter.qc
qcsrc/common/triggers/trigger/counter.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/delay.qc
qcsrc/common/triggers/trigger/delay.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/disablerelay.qc
qcsrc/common/triggers/trigger/disablerelay.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/flipflop.qc
qcsrc/common/triggers/trigger/flipflop.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/gamestart.qc
qcsrc/common/triggers/trigger/gamestart.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/gravity.qc
qcsrc/common/triggers/trigger/gravity.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/heal.qc
qcsrc/common/triggers/trigger/heal.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/hurt.qc
qcsrc/common/triggers/trigger/hurt.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/impulse.qc
qcsrc/common/triggers/trigger/jumppads.qc
qcsrc/common/triggers/trigger/keylock.qc
qcsrc/common/triggers/trigger/magicear.qc
qcsrc/common/triggers/trigger/magicear.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/monoflop.qc
qcsrc/common/triggers/trigger/monoflop.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/multi.qc
qcsrc/common/triggers/trigger/multivibrator.qc
qcsrc/common/triggers/trigger/multivibrator.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/relay.qc
qcsrc/common/triggers/trigger/relay.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/relay_activators.qc
qcsrc/common/triggers/trigger/relay_activators.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/relay_if.qc
qcsrc/common/triggers/trigger/relay_if.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/relay_teamcheck.qc
qcsrc/common/triggers/trigger/relay_teamcheck.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/secret.qc
qcsrc/common/triggers/trigger/swamp.qc
qcsrc/common/triggers/trigger/teleport.qc
qcsrc/common/triggers/trigger/teleport.qh [new file with mode: 0644]
qcsrc/common/triggers/trigger/viewloc.qc
qcsrc/common/triggers/triggers.qc
qcsrc/common/triggers/triggers.qh
qcsrc/common/turrets/_all.inc [new file with mode: 0644]
qcsrc/common/turrets/_all.qh [new file with mode: 0644]
qcsrc/common/turrets/_mod.inc
qcsrc/common/turrets/_mod.qh
qcsrc/common/turrets/all.qh
qcsrc/common/turrets/checkpoint.qc
qcsrc/common/turrets/checkpoint.qh [new file with mode: 0644]
qcsrc/common/turrets/cl_turrets.qc
qcsrc/common/turrets/cl_turrets.qh [new file with mode: 0644]
qcsrc/common/turrets/config.qc
qcsrc/common/turrets/sv_turrets.qc
qcsrc/common/turrets/targettrigger.qc
qcsrc/common/turrets/targettrigger.qh [new file with mode: 0644]
qcsrc/common/turrets/turret.qh
qcsrc/common/turrets/turret/ewheel.qc
qcsrc/common/turrets/turret/ewheel.qh [new file with mode: 0644]
qcsrc/common/turrets/turret/flac.qc
qcsrc/common/turrets/turret/flac.qh [new file with mode: 0644]
qcsrc/common/turrets/turret/fusionreactor.qc
qcsrc/common/turrets/turret/fusionreactor.qh [new file with mode: 0644]
qcsrc/common/turrets/turret/hellion.qc
qcsrc/common/turrets/turret/hellion.qh [new file with mode: 0644]
qcsrc/common/turrets/turret/hk.qc
qcsrc/common/turrets/turret/hk.qh [new file with mode: 0644]
qcsrc/common/turrets/turret/machinegun.qc
qcsrc/common/turrets/turret/machinegun.qh [new file with mode: 0644]
qcsrc/common/turrets/turret/mlrs.qc
qcsrc/common/turrets/turret/mlrs.qh [new file with mode: 0644]
qcsrc/common/turrets/turret/phaser.qc
qcsrc/common/turrets/turret/phaser.qh [new file with mode: 0644]
qcsrc/common/turrets/turret/phaser_weapon.qc
qcsrc/common/turrets/turret/plasma.qc
qcsrc/common/turrets/turret/plasma.qh [new file with mode: 0644]
qcsrc/common/turrets/turret/plasma_dual.qc
qcsrc/common/turrets/turret/plasma_dual.qh [new file with mode: 0644]
qcsrc/common/turrets/turret/tesla.qc
qcsrc/common/turrets/turret/tesla.qh [new file with mode: 0644]
qcsrc/common/turrets/turret/walker.qc
qcsrc/common/turrets/turret/walker.qh [new file with mode: 0644]
qcsrc/common/turrets/turrets.qc [new file with mode: 0644]
qcsrc/common/turrets/turrets.qh [new file with mode: 0644]
qcsrc/common/turrets/util.qc
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/common/vehicles/_all.inc [new file with mode: 0644]
qcsrc/common/vehicles/_all.qh [new file with mode: 0644]
qcsrc/common/vehicles/_mod.inc
qcsrc/common/vehicles/_mod.qh
qcsrc/common/vehicles/all.qc
qcsrc/common/vehicles/cl_vehicles.qc
qcsrc/common/vehicles/sv_vehicles.qc
qcsrc/common/vehicles/sv_vehicles.qh
qcsrc/common/vehicles/vehicle/bumblebee.qc
qcsrc/common/vehicles/vehicle/bumblebee.qh
qcsrc/common/vehicles/vehicle/bumblebee_weapons.qh
qcsrc/common/vehicles/vehicle/racer.qc
qcsrc/common/vehicles/vehicle/racer.qh [new file with mode: 0644]
qcsrc/common/vehicles/vehicle/racer_weapon.qh
qcsrc/common/vehicles/vehicle/raptor.qc
qcsrc/common/vehicles/vehicle/raptor.qh
qcsrc/common/vehicles/vehicle/raptor_weapons.qc
qcsrc/common/vehicles/vehicle/raptor_weapons.qh
qcsrc/common/vehicles/vehicle/spiderbot.qc
qcsrc/common/vehicles/vehicle/spiderbot.qh [new file with mode: 0644]
qcsrc/common/vehicles/vehicle/spiderbot_weapons.qc
qcsrc/common/vehicles/vehicle/spiderbot_weapons.qh
qcsrc/common/vehicles/vehicles.qc [new file with mode: 0644]
qcsrc/common/vehicles/vehicles.qh [new file with mode: 0644]
qcsrc/common/viewloc.qc
qcsrc/common/weapons/_all.inc [new file with mode: 0644]
qcsrc/common/weapons/_all.qh [new file with mode: 0644]
qcsrc/common/weapons/all.qc
qcsrc/common/weapons/all.qh
qcsrc/common/weapons/calculations.qc
qcsrc/common/weapons/calculations.qh
qcsrc/common/weapons/config.qc
qcsrc/common/weapons/weapon.qh
qcsrc/common/weapons/weapon/arc.qc
qcsrc/common/weapons/weapon/arc.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/blaster.qc
qcsrc/common/weapons/weapon/blaster.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/crylink.qc
qcsrc/common/weapons/weapon/crylink.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/devastator.qc
qcsrc/common/weapons/weapon/devastator.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/electro.qc
qcsrc/common/weapons/weapon/electro.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/fireball.qc
qcsrc/common/weapons/weapon/fireball.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/hagar.qc
qcsrc/common/weapons/weapon/hagar.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/hlac.qc
qcsrc/common/weapons/weapon/hlac.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/hook.qc
qcsrc/common/weapons/weapon/hook.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/machinegun.qc
qcsrc/common/weapons/weapon/machinegun.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/minelayer.qc
qcsrc/common/weapons/weapon/minelayer.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/mortar.qc
qcsrc/common/weapons/weapon/mortar.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/porto.qc
qcsrc/common/weapons/weapon/porto.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/rifle.qc
qcsrc/common/weapons/weapon/rifle.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/seeker.qc
qcsrc/common/weapons/weapon/seeker.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/shockwave.qc
qcsrc/common/weapons/weapon/shockwave.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/shotgun.qc
qcsrc/common/weapons/weapon/shotgun.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/tuba.qc
qcsrc/common/weapons/weapon/tuba.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/vaporizer.qc
qcsrc/common/weapons/weapon/vaporizer.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/vortex.qc
qcsrc/common/weapons/weapon/vortex.qh [new file with mode: 0644]
qcsrc/dpdefs/post.qh
qcsrc/dpdefs/pre.qh
qcsrc/ecs/_lib.inc [deleted file]
qcsrc/ecs/_lib.qh [deleted file]
qcsrc/ecs/_mod.inc
qcsrc/ecs/_mod.qh
qcsrc/ecs/lib.qh [new file with mode: 0644]
qcsrc/ecs/main.qh
qcsrc/lib/_all.inc
qcsrc/lib/angle.qh [new file with mode: 0644]
qcsrc/lib/csqcmodel/_mod.inc
qcsrc/lib/csqcmodel/_mod.qh
qcsrc/lib/csqcmodel/model.qc [new file with mode: 0644]
qcsrc/lib/csqcmodel/model.qh [new file with mode: 0644]
qcsrc/lib/csqcmodel/player.qc [new file with mode: 0644]
qcsrc/lib/csqcmodel/player.qh [new file with mode: 0644]
qcsrc/lib/defer.qh
qcsrc/lib/intrusivelist.qh
qcsrc/lib/iter.qh
qcsrc/lib/json.qh [new file with mode: 0644]
qcsrc/lib/matrix/command.qc
qcsrc/lib/net.qh
qcsrc/lib/replicate.qh
qcsrc/lib/self.qh
qcsrc/lib/vector.qh
qcsrc/lib/warpzone/common.qc
qcsrc/lib/warpzone/server.qc
qcsrc/menu/_all.inc [new file with mode: 0644]
qcsrc/menu/auto-super.pl [deleted file]
qcsrc/menu/command/_mod.inc
qcsrc/menu/command/_mod.qh
qcsrc/menu/command/all.qc [deleted file]
qcsrc/menu/command/all.qh [deleted file]
qcsrc/menu/command/menu_cmd.qc
qcsrc/menu/menu.qc
qcsrc/menu/progs.inc
qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc
qcsrc/menu/xonotic/keybinder.qc
qcsrc/menu/xonotic/playermodel.qc
qcsrc/menu/xonotic/util.qc
qcsrc/menu/xonotic/weaponslist.qc
qcsrc/server/_all.inc [new file with mode: 0644]
qcsrc/server/_mod.inc
qcsrc/server/_mod.qh
qcsrc/server/autocvars.qh
qcsrc/server/bot/_mod.inc
qcsrc/server/bot/_mod.qh
qcsrc/server/bot/api.qc
qcsrc/server/bot/api.qh
qcsrc/server/bot/default/_mod.inc
qcsrc/server/bot/default/_mod.qh
qcsrc/server/bot/default/aim.qc
qcsrc/server/bot/default/bot.qc
qcsrc/server/bot/default/havocbot/havocbot.qc
qcsrc/server/bot/default/havocbot/roles.qc
qcsrc/server/bot/default/havocbot/roles.qh
qcsrc/server/bot/default/navigation.qc
qcsrc/server/bot/default/scripting.qc
qcsrc/server/bot/default/waypoints.qc
qcsrc/server/bot/null/_mod.inc [new file with mode: 0644]
qcsrc/server/bot/null/_mod.qh [new file with mode: 0644]
qcsrc/server/bot/null/bot_null.qc [new file with mode: 0644]
qcsrc/server/bot/null/bot_null.qh [new file with mode: 0644]
qcsrc/server/cheats.qc
qcsrc/server/cl_client.qc [deleted file]
qcsrc/server/cl_client.qh [deleted file]
qcsrc/server/cl_impulse.qc [deleted file]
qcsrc/server/cl_impulse.qh [deleted file]
qcsrc/server/cl_player.qc [deleted file]
qcsrc/server/cl_player.qh [deleted file]
qcsrc/server/client.qc [new file with mode: 0644]
qcsrc/server/client.qh [new file with mode: 0644]
qcsrc/server/command/_mod.inc
qcsrc/server/command/_mod.qh
qcsrc/server/command/all.qc [deleted file]
qcsrc/server/command/all.qh [deleted file]
qcsrc/server/command/banning.qc
qcsrc/server/command/cmd.qc
qcsrc/server/command/common.qc
qcsrc/server/command/common.qh
qcsrc/server/command/getreplies.qc
qcsrc/server/command/radarmap.qc
qcsrc/server/command/reg.qc [new file with mode: 0644]
qcsrc/server/command/reg.qh [new file with mode: 0644]
qcsrc/server/command/sv_cmd.qc
qcsrc/server/command/vote.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_damage.qh
qcsrc/server/g_hook.qc
qcsrc/server/g_world.qc
qcsrc/server/impulse.qc [new file with mode: 0644]
qcsrc/server/impulse.qh [new file with mode: 0644]
qcsrc/server/item_key.qc
qcsrc/server/matrix.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/_mod.inc
qcsrc/server/mutators/_mod.qh
qcsrc/server/mutators/all.inc [deleted file]
qcsrc/server/mutators/all.qc [deleted file]
qcsrc/server/mutators/all.qh [deleted file]
qcsrc/server/mutators/events.qh
qcsrc/server/mutators/gamemode.qh
qcsrc/server/mutators/loader.qc [new file with mode: 0644]
qcsrc/server/mutators/loader.qh [new file with mode: 0644]
qcsrc/server/mutators/mutator.qh
qcsrc/server/mutators/mutator/gamemode_assault.qc
qcsrc/server/mutators/mutator/gamemode_assault.qh
qcsrc/server/mutators/mutator/gamemode_ca.qc
qcsrc/server/mutators/mutator/gamemode_ca.qh
qcsrc/server/mutators/mutator/gamemode_ctf.qc
qcsrc/server/mutators/mutator/gamemode_cts.qc
qcsrc/server/mutators/mutator/gamemode_cts.qh
qcsrc/server/mutators/mutator/gamemode_deathmatch.qc
qcsrc/server/mutators/mutator/gamemode_deathmatch.qh
qcsrc/server/mutators/mutator/gamemode_domination.qc
qcsrc/server/mutators/mutator/gamemode_domination.qh
qcsrc/server/mutators/mutator/gamemode_freezetag.qc
qcsrc/server/mutators/mutator/gamemode_freezetag.qh
qcsrc/server/mutators/mutator/gamemode_invasion.qc
qcsrc/server/mutators/mutator/gamemode_invasion.qh
qcsrc/server/mutators/mutator/gamemode_keepaway.qc
qcsrc/server/mutators/mutator/gamemode_keepaway.qh
qcsrc/server/mutators/mutator/gamemode_keyhunt.qc
qcsrc/server/mutators/mutator/gamemode_keyhunt.qh
qcsrc/server/mutators/mutator/gamemode_lms.qc
qcsrc/server/mutators/mutator/gamemode_lms.qh
qcsrc/server/mutators/mutator/gamemode_race.qc
qcsrc/server/mutators/mutator/gamemode_race.qh
qcsrc/server/mutators/mutator/gamemode_tdm.qc
qcsrc/server/mutators/mutator/gamemode_tdm.qh
qcsrc/server/pathlib/_all.inc [deleted file]
qcsrc/server/pathlib/costs.qc
qcsrc/server/pathlib/costs.qh
qcsrc/server/pathlib/debug.qc
qcsrc/server/pathlib/debug.qh
qcsrc/server/pathlib/pathlib.qh
qcsrc/server/player.qc [new file with mode: 0644]
qcsrc/server/player.qh [new file with mode: 0644]
qcsrc/server/portals.qc
qcsrc/server/progs.inc
qcsrc/server/race.qc
qcsrc/server/race.qh
qcsrc/server/scores.qc
qcsrc/server/scores_rules.qc
qcsrc/server/spawnpoints.qc
qcsrc/server/steerlib.qc
qcsrc/server/steerlib.qh
qcsrc/server/sv_main.qc
qcsrc/server/t_quake.qc
qcsrc/server/t_quake3.qc
qcsrc/server/teamplay.qc
qcsrc/server/teamplay.qh
qcsrc/server/tests.qh
qcsrc/server/weapons/accuracy.qc
qcsrc/server/weapons/common.qc
qcsrc/server/weapons/csqcprojectile.qc
qcsrc/server/weapons/hitplot.qc
qcsrc/server/weapons/selection.qc
qcsrc/server/weapons/spawning.qc
qcsrc/server/weapons/throwing.qc
qcsrc/server/weapons/tracing.qc
qcsrc/server/weapons/weaponstats.qc
qcsrc/server/weapons/weaponsystem.qc
qcsrc/tools/auto-super.pl [new file with mode: 0644]
qcsrc/tools/compilationunits.sh
qcsrc/tools/genmod.sh
qcsrc/tools/headerstyle.sh
qcsrc/tools/qcc.sh

index 8838f39c9734b2fbb015b615c68e645cb487dd22..afd12e592f5e3a5de8dbc67cce4461b2d8efe74b 100644 (file)
@@ -30,7 +30,7 @@ test_sv_game:
     - wget -O data/maps/g-23.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/g-23.waypoints.cache
     - wget -O data/maps/g-23.waypoints.hardwired https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/g-23.waypoints.hardwired
     - make
-    - EXPECT=74f3802009cec230bdaa3b87235368ca
+    - EXPECT=b46b7dcf27e864c2842b7436e32e24fe
     - HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
       | tee /dev/stderr
       | grep '^:'
index fdbce7d5ac19f8b20fd5990f9756af7773ea05ba..2f38e43ba2be7ad75167b6683b238baae72dbc1a 100644 (file)
@@ -26,11 +26,11 @@ set_source_files_properties(
 )
 
 add_executable(csprogs qcsrc/client/progs.inc)
-target_compile_definitions(csprogs PRIVATE -DCSQC)
+target_compile_definitions(csprogs PRIVATE -DGAMEQC -DCSQC)
 add_dependencies(csprogs gmqcc)
 
 add_executable(progs qcsrc/server/progs.inc)
-target_compile_definitions(progs PRIVATE -DSVQC)
+target_compile_definitions(progs PRIVATE -DGAMEQC -DSVQC)
 add_dependencies(progs gmqcc)
 
 add_executable(menu qcsrc/menu/progs.inc)
index d2731c0732e2623c2dda636e5d367622546a1a26..538e3549fc5cc41ca4d8bebb03226129243a0f4a 100644 (file)
@@ -1024,13 +1024,13 @@ sv_allowdownloads 0 // download protocol is evil
 
 set g_jump_grunt 0     "Do you make a grunting noise every time you jump? Is it the same grunting noise every time?"
 
-seta cl_weaponpriority "vaporizer vortex fireball mortar machinegun hagar rifle arc electro devastator crylink minelayer shotgun shockwave hlac tuba blaster porto seeker hook" "weapon priority list"
+seta cl_weaponpriority "vaporizer hmg rpc vortex fireball mortar machinegun hagar rifle arc electro devastator crylink minelayer shotgun shockwave hlac tuba blaster porto seeker hook" "weapon priority list"
 seta cl_weaponpriority_useforcycling 0 "when set, weapon cycling by the mouse wheel makes use of the weapon priority list (the special value 2 uses the weapon ID list for cycling)"
-seta cl_weaponpriority0 "devastator mortar hagar seeker fireball"                       "use weapon_priority_0_prev for prev gun from this list, weapon_priority_0_best for best gun, weapon_priority_0_next for next gun.  Default value: explosives"
+seta cl_weaponpriority0 "rpc devastator mortar hagar seeker fireball"                   "use weapon_priority_0_prev for prev gun from this list, weapon_priority_0_best for best gun, weapon_priority_0_next for next gun.  Default value: explosives"
 seta cl_weaponpriority1 "vaporizer vortex crylink hlac arc electro blaster shockwave"   "use weapon_priority_1_prev for prev gun from this list, weapon_priority_1_best for best gun, weapon_priority_1_next for next gun.  Default value: energy"
 seta cl_weaponpriority2 "vaporizer vortex rifle"                                        "use weapon_priority_2_prev for prev gun from this list, weapon_priority_2_best for best gun, weapon_priority_2_next for next gun.  Default value: hitscan exact"
-seta cl_weaponpriority3 "vaporizer vortex rifle machinegun shotgun shockwave"                     "use weapon_priority_3_prev for prev gun from this list, weapon_priority_3_best for best gun, weapon_priority_3_next for next gun.  Default value: hitscan all"
-seta cl_weaponpriority4 "mortar minelayer hlac hagar crylink seeker shotgun shockwave"            "use weapon_priority_4_prev for prev gun from this list, weapon_priority_4_best for best gun, weapon_priority_4_next for next gun.  Default value: spam weapons"
+seta cl_weaponpriority3 "vaporizer hmg vortex rifle machinegun shotgun shockwave"       "use weapon_priority_3_prev for prev gun from this list, weapon_priority_3_best for best gun, weapon_priority_3_next for next gun.  Default value: hitscan all"
+seta cl_weaponpriority4 "mortar minelayer hlac hagar crylink seeker shotgun shockwave"  "use weapon_priority_4_prev for prev gun from this list, weapon_priority_4_best for best gun, weapon_priority_4_next for next gun.  Default value: spam weapons"
 seta cl_weaponpriority5 "blaster shockwave hook porto"                                  "use weapon_priority_5_prev for prev gun from this list, weapon_priority_5_best for best gun, weapon_priority_5_next for next gun.  Default value: weapons for moving"
 seta cl_weaponpriority6 ""                                                              "use weapon_priority_6_prev for prev gun from this list, weapon_priority_6_best for best gun, weapon_priority_6_next for next gun"
 seta cl_weaponpriority7 ""                                                              "use weapon_priority_7_prev for prev gun from this list, weapon_priority_7_best for best gun, weapon_priority_7_next for next gun"
index 4cf77d52e39bd0373c320cf4231372f5864f633f..add2332726f51f1eb52df2f2e495a9be791f0693 100644 (file)
@@ -391,7 +391,7 @@ set g_freezetag_teams 0
 // ==========
 //  keepaway
 // ==========
-set g_keepaway 0 "game mode which focuses around a ball, look at g_keepaway_win_mode for further details"
+set g_keepaway 0 "game mode which focuses around a ball"
 set g_keepaway_score_bckill 1 "enable scoring points (y/n) for ball carrier kills (value is how many points to award)"
 set g_keepaway_score_killac 1 "amount of points to give when you kill someone while you have the ball"
 set g_keepaway_score_timeinterval 1 "amount of time it takes between intervals for timepoints to be added to the score"
index f75a15fb8ef55b3cf7b06abeaec7ba451ae9ab9f..f4b62dea70bce940d29eb41f959c5e349580dd6f 100644 (file)
@@ -11,3 +11,4 @@ bone_aim2 0.2 upperarm_L
 bone_aim3 0.35 bip01 r hand
 bone_weapon bip01 r hand
 fixbone 1
+hidden 1
index 1932354e8078c3f24947504da7bbb93390c5a51a..7533a4c53adab086fe9866c766df919d631666f7 100644 (file)
@@ -1,2 +1,2 @@
 pyria_obj.001,pyriahair
-pyria_obj,pyriafullbright
+pyria_obj,pyria
index 1932354e8078c3f24947504da7bbb93390c5a51a..7533a4c53adab086fe9866c766df919d631666f7 100644 (file)
@@ -1,2 +1,2 @@
 pyria_obj.001,pyriahair
-pyria_obj,pyriafullbright
+pyria_obj,pyria
index 1932354e8078c3f24947504da7bbb93390c5a51a..7533a4c53adab086fe9866c766df919d631666f7 100644 (file)
@@ -1,2 +1,2 @@
 pyria_obj.001,pyriahair
-pyria_obj,pyriafullbright
+pyria_obj,pyria
index 7b94ebe4a4e61e1d7e0803fb86a91a60fb3ecf4e..7138ad587e31e81451b941144041fa5ffec81ec0 100644 (file)
@@ -1,2 +1,2 @@
-ignis42,ignisfullbright
+ignis42,ignis
 ignis42.002,ignishead
index 7b94ebe4a4e61e1d7e0803fb86a91a60fb3ecf4e..7138ad587e31e81451b941144041fa5ffec81ec0 100644 (file)
@@ -1,2 +1,2 @@
-ignis42,ignisfullbright
+ignis42,ignis
 ignis42.002,ignishead
index 7b94ebe4a4e61e1d7e0803fb86a91a60fb3ecf4e..7138ad587e31e81451b941144041fa5ffec81ec0 100644 (file)
@@ -1,2 +1,2 @@
-ignis42,ignisfullbright
+ignis42,ignis
 ignis42.002,ignishead
index f6eca00d004e4196ffff60499b30a5ab44bed257..b5a97f87a52db532a16eea6cc85d5ac5d54eca34 100644 (file)
@@ -93,6 +93,8 @@ set g_monsters_skill 1 "Monster skill (affecting some of their attributes). 1 -
 set g_monsters_miniboss_chance 5
 set g_monsters_miniboss_healthboost 100
 set g_monsters_drop_time 10
+set g_monsters_ignoretraces 1
+set g_monsters_lineofsight 1
 set g_monsters_owners 1
 set g_monsters_teams 1
 set g_monsters_score_kill 0
index 09d0128578d272c49812442b4d840efc7eede915..06ee7468ddd83bfbb93c83a15e0fe61a0d6ae45f 100644 (file)
@@ -1997,6 +1997,7 @@ INCLUDE_FILE_PATTERNS  =
 # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 PREDEFINED             = \
+    "XONOTIC" \
     "USING(name, T)=using name = T" \
     "CLASS(name, base)=class name : public base { public:" \
     "INIT(class)=class::class()" \
index 0ed67281b4259d18fdd466d6f29912b94f011a63..903d8537e695bf35b33fb78889c814a38536cf7b 100644 (file)
@@ -8,7 +8,7 @@ QCCFLAGS_WATERMARK ?= $(shell git describe --tags --dirty='~')
 VER = $(subst *,\*,$(QCCFLAGS_WATERMARK))
 NDEBUG ?= 1
 XONOTIC ?= 1
-BUILD_MOD ?= 0
+BUILD_MOD ?=
 
 ifndef ZIP
        ifneq ($(shell which zip),)
@@ -34,7 +34,7 @@ QCCDEFS ?= \
        -DXONOTIC=$(XONOTIC) \
        -DWATERMARK="$(QCCFLAGS_WATERMARK)" \
        -DNDEBUG=$(NDEBUG) \
-       -DBUILD_MOD=$(BUILD_MOD) \
+       $(if $(BUILD_MOD), -DBUILD_MOD="$(BUILD_MOD)" -I$(BUILD_MOD), ) \
        $(QCCDEFS_EXTRA)
 
 # -Ooverlap-locals is required
diff --git a/qcsrc/client/_all.inc b/qcsrc/client/_all.inc
new file mode 100644 (file)
index 0000000..f592f8a
--- /dev/null
@@ -0,0 +1,20 @@
+#include <client/_all.qh>
+#include "_mod.inc"
+
+#include "commands/_mod.inc"
+#include "hud/_mod.inc"
+#include "mutators/_mod.inc"
+#include "weapons/_mod.inc"
+
+#include <common/_all.inc>
+#include <common/effects/qc/all.qc>
+
+#include <lib/csqcmodel/cl_model.qc>
+#include <lib/csqcmodel/cl_player.qc>
+#include <lib/csqcmodel/interpolate.qc>
+
+#include <lib/warpzone/anglestransform.qc>
+#include <lib/warpzone/common.qc>
+#include <lib/warpzone/client.qc>
+#include <lib/warpzone/server.qc>
+#include <lib/warpzone/util_server.qc>
index 746734dee2011e048533d0113c4d59a089ea4e82..077b5f450a5ff2eee4b0ca4dd52a5aee382c77ee 100644 (file)
@@ -1,4 +1,5 @@
 #pragma once
+//#include "_mod.qh"
 
 #include <common/util.qh>
 
@@ -10,3 +11,5 @@
 #include "defs.qh"
 #include "main.qh"
 #include "miscfunctions.qh"
+
+#include <common/ent_cs.qh>
index 65a21972074e6806c5a864db6ed6dbe118fa421f..25ab0e2a053fcfe0ff45703a880a62f87d5724c3 100644 (file)
@@ -324,7 +324,6 @@ bool autocvar_hud_panel_timer_increment;
 float autocvar_hud_panel_update_interval;
 bool autocvar_hud_panel_vote;
 float autocvar_hud_panel_vote_alreadyvoted_alpha;
-string autocvar_hud_panel_vote_bg_alpha;
 bool autocvar_hud_panel_weapons;
 bool autocvar_hud_panel_weapons_accuracy;
 bool autocvar_hud_panel_weapons_ammo;
index 235f1297fda6e5c7fdc3d6b43c3cab94e0af6109..dcfc6ecea56e94103c08ae21a99997bf815dff72 100644 (file)
@@ -1,3 +1,4 @@
 // generated file; do not modify
-#include <client/commands/all.qc>
-#include <client/commands/cl_cmd.qc>
+#ifdef CSQC
+    #include <client/commands/cl_cmd.qc>
+#endif
index 03df56398ccf89c0e09f1a70011698f8e1465d50..7829965a2350f0bb075fd0431447aabe030f7d57 100644 (file)
@@ -1,3 +1,4 @@
 // generated file; do not modify
-#include <client/commands/all.qh>
-#include <client/commands/cl_cmd.qh>
+#ifdef CSQC
+    #include <client/commands/cl_cmd.qh>
+#endif
diff --git a/qcsrc/client/commands/all.qc b/qcsrc/client/commands/all.qc
deleted file mode 100644 (file)
index bc15eeb..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "all.qh"
-#include <common/command/all.qc>
diff --git a/qcsrc/client/commands/all.qh b/qcsrc/client/commands/all.qh
deleted file mode 100644 (file)
index 2df61f0..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-
-#include <common/command/all.qh>
-
-#include "cl_cmd.qh"
index 9b8f58f94418e13163a120c30eaefcb3f37bc886..631090cc1f9b7d119a2a9847b9d6ee5619cdd568 100644 (file)
@@ -4,12 +4,12 @@
 //  Last updated: December 28th, 2011
 // ==============================================
 
-#include <common/command/command.qh>
+#include <common/command/_mod.qh>
 #include "cl_cmd.qh"
 
 #include "../autocvars.qh"
 #include "../defs.qh"
-#include <client/hud/all.qh>
+#include <client/hud/_mod.qh>
 #include "../main.qh"
 #include "../mapvoting.qh"
 #include "../miscfunctions.qh"
@@ -18,8 +18,6 @@
 
 #include <common/mapinfo.qh>
 
-#include <common/command/generic.qh>
-
 void DrawDebugModel(entity this)
 {
        if (time - floor(time) > 0.5)
index d6ee5f8f79add97bf2dfded05615e01788260bab..0643bb09d5b37e3bdd7b014f13964959ab837484 100644 (file)
@@ -3,6 +3,7 @@
 #include "player_skeleton.qh"
 #include "weapons/projectile.qh"
 #include <common/animdecide.qh>
+#include <common/ent_cs.qh>
 #include <common/physics/movetypes/movetypes.qh>
 #include <common/viewloc.qh>
 #include <lib/csqcmodel/cl_model.qh>
@@ -192,7 +193,7 @@ void CSQCPlayer_ModelAppearance_Apply(entity this, bool islocalplayer)
        bool isfriend;
        int cm;
        cm = this.forceplayermodels_savecolormap;
-       cm = (cm >= 1024) ? cm : (stof(getplayerkeyvalue(cm - 1, "colors")) + 1024);
+       cm = (cm >= 1024) ? cm : (entcs_GetClientColors(cm - 1) + 1024);
 
        if(teamplay)
                isfriend = (cm == 1024 + 17 * myteam);
@@ -279,7 +280,7 @@ void CSQCPlayer_ModelAppearance_Apply(entity this, bool islocalplayer)
 
        // GLOWMOD AND DEATH FADING
        if(this.colormap > 0)
-               this.glowmod = colormapPaletteColor(((this.colormap >= 1024) ? this.colormap : stof(getplayerkeyvalue(this.colormap - 1, "colors"))) & 0x0F, true) * 2;
+               this.glowmod = colormapPaletteColor(((this.colormap >= 1024) ? this.colormap : entcs_GetClientColors(this.colormap - 1)) & 0x0F, true) * 2;
        else
                this.glowmod = '1 1 1';
 
index e62f0704f16119b2236c847d90abeba704347da5..182f6ace743c71437f9a9f6fb6d323abf6bf21cc 100644 (file)
@@ -120,6 +120,8 @@ int serverflags;
 
 float uid2name_dialog;
 
+float gameover_time;
+
 .bool csqcmodel_isdead; // used by shownames and miscfunctions (entcs_IsDead) to know when a player is dead
 
 #define player_currententnum (spectatee_status > 0 ? spectatee_status : player_localnum + 1)
index b90f61b8cc443286de41af3507cfbf146f8c988c..aa785a9e94c5524789bf7e47dbe0adeebe6ed8c3 100644 (file)
@@ -1,3 +1,6 @@
 // generated file; do not modify
 #include <client/hud/hud.qc>
 #include <client/hud/hud_config.qc>
+#include <client/hud/panel.qc>
+
+#include <client/hud/panel/_mod.inc>
index ee9ac8f76f56736a9f05f6d0a60834abf3849b99..2d4850d521d360565cacf66e4dabf3e7949f6d66 100644 (file)
@@ -1,3 +1,6 @@
 // generated file; do not modify
 #include <client/hud/hud.qh>
 #include <client/hud/hud_config.qh>
+#include <client/hud/panel.qh>
+
+#include <client/hud/panel/_mod.qh>
diff --git a/qcsrc/client/hud/all.inc b/qcsrc/client/hud/all.inc
deleted file mode 100644 (file)
index 8305304..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#include "panel/weapons.qc"
-#include "panel/ammo.qc"
-#include "panel/powerups.qc"
-#include "panel/healtharmor.qc"
-#include "panel/notify.qc"
-#include "panel/timer.qc"
-#include "panel/radar.qc"
-#include "panel/score.qc"
-#include "panel/racetimer.qc"
-#include "panel/vote.qc"
-#include "panel/modicons.qc"
-#include "panel/pressedkeys.qc"
-#include "panel/chat.qc"
-#include "panel/engineinfo.qc"
-#include "panel/infomessages.qc"
-#include "panel/physics.qc"
-#include "panel/centerprint.qc"
-#include "panel/minigame.qc"
-// #include "panel/mapvote.qc"
-// #include "panel/itemstime.qc"
-#include "panel/quickmenu.qc"
-#include "panel/scoreboard.qc"
diff --git a/qcsrc/client/hud/all.qh b/qcsrc/client/hud/all.qh
deleted file mode 100644 (file)
index 2e458e6..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#pragma once
-
-#include "hud.qh"
-#include "hud_config.qh"
index c87e733e1d4e633dc2bd28e815d8c885c89ab22e..d200e2c6c522e67f05b009f301f9a03f5677d9db 100644 (file)
@@ -1,11 +1,12 @@
 #include "hud.qh"
 
+#include "panel/scoreboard.qh"
 #include "hud_config.qh"
 #include "../mapvoting.qh"
 #include "../teamradar.qh"
 #include <common/t_items.qh>
 #include <common/deathtypes/all.qh>
-#include <common/items/all.qc>
+#include <common/items/_mod.qh>
 #include <common/mapinfo.qh>
 #include <common/vehicles/all.qh>
 #include <common/mutators/mutator/waypoints/all.qh>
@@ -334,8 +335,6 @@ void DrawNumIcon(vector myPos, vector mySize, float x, string icon, bool vertica
        DrawNumIcon_expanding(myPos, mySize, x, icon, vertical, icon_right_align, color, theAlpha, 0);
 }
 
-#include "all.inc"
-
 /*
 ==================
 Main HUD system
@@ -357,26 +356,47 @@ void HUD_Vehicle()
        }
 }
 
-bool HUD_Panel_CheckFlags(int showflags)
-{
-    TC(int, showflags);
-       if ( HUD_Minigame_Showpanels() )
-               return showflags & PANEL_SHOW_MINIGAME;
-       if(intermission == 2)
-               return showflags & PANEL_SHOW_MAPVOTE;
-       return showflags & PANEL_SHOW_MAINGAME;
-}
+bool HUD_Minigame_Showpanels();
 
 void HUD_Panel_Draw(entity panent)
 {
        panel = panent;
-       if(autocvar__hud_configure)
+       if (autocvar__hud_configure)
+       {
+               if (!(panel.panel_configflags & PANEL_CONFIG_MAIN))
+                       return;
+               panel_fade_alpha = 1;
+               Hud_Panel_GetPanelEnabled();
+               panel.panel_draw();
+               return;
+       }
+
+       bool draw_allowed = false;
+       if (HUD_Minigame_Showpanels())
+       {
+               if (panel.panel_showflags & PANEL_SHOW_MINIGAME)
+                       draw_allowed = true;
+       }
+       else if(intermission == 2)
        {
-               if(panel.panel_configflags & PANEL_CONFIG_MAIN)
-                       panel.panel_draw();
+               if(panel.panel_showflags & PANEL_SHOW_MAPVOTE)
+                       draw_allowed = true;
        }
-       else if(HUD_Panel_CheckFlags(panel.panel_showflags))
+       else if (panel.panel_showflags & PANEL_SHOW_MAINGAME)
+               draw_allowed = true;
+
+       if (draw_allowed)
+       {
+               if (panel.panel_showflags & PANEL_SHOW_WITH_SB)
+                       panel_fade_alpha = 1;
+               else
+               {
+                       panel_fade_alpha = 1 - scoreboard_fade_alpha;
+                       if(!panel_fade_alpha)
+                               return;
+               }
                panel.panel_draw();
+       }
 }
 
 void HUD_Reset()
@@ -413,6 +433,7 @@ bool Hud_Shake_Update()
        return true;
 }
 
+entity CSQCModel_server2csqc(int i);
 void calc_followmodel_ofs(entity view);
 void Hud_Dynamic_Frame()
 {
@@ -492,11 +513,8 @@ void Hud_Dynamic_Frame()
 void HUD_Main()
 {
        int i;
-       // global hud alpha fade (scoreboard-related panels behave differently and override it temporarly)
        if(hud_configure_menu_open == 1)
                hud_fade_alpha = 1;
-       else if(!autocvar__hud_configure)
-               hud_fade_alpha = (1 - scoreboard_fade_alpha) * (1 - autocvar__menu_alpha);
        else
                hud_fade_alpha = 1 - autocvar__menu_alpha;
 
@@ -504,27 +522,9 @@ void HUD_Main()
 
        Hud_Dynamic_Frame();
 
-       // panels that we want to be active together with the scoreboard
-       // they must fade only when the menu does
        if(scoreboard_fade_alpha == 1)
-       {
                if(autocvar__menu_alpha == 1)
                        return;
-               if(scoreboard_fade_alpha == 1)
-               {
-                       HUD_Panel_Draw(HUD_PANEL(SCOREBOARD));
-                       HUD_Panel_Draw(HUD_PANEL(CENTERPRINT));
-                       return;
-               }
-       }
-
-       if(!autocvar__hud_configure && !hud_fade_alpha)
-       {
-               hud_fade_alpha = 1;
-               HUD_Panel_Draw(HUD_PANEL(VOTE));
-               hud_fade_alpha = 0;
-               return;
-       }
 
        // Drawing stuff
        if (hud_skin_prev != autocvar_hud_skin)
@@ -556,11 +556,11 @@ void HUD_Main()
                {
                        string hud_dock_color = autocvar_hud_dock_color;
                        if(hud_dock_color == "shirt") {
-                               f = stof(getplayerkeyvalue(current_player, "colors"));
+                               f = entcs_GetClientColors(current_player);
                                color = colormapPaletteColor(floor(f / 16), 0);
                        }
                        else if(hud_dock_color == "pants") {
-                               f = stof(getplayerkeyvalue(current_player, "colors"));
+                               f = entcs_GetClientColors(current_player);
                                color = colormapPaletteColor(f % 16, 1);
                        }
                        else
@@ -635,8 +635,9 @@ void HUD_Main()
                HUD_Panel_Draw(HUD_PANEL(CHAT));
        if(hud_panel_quickmenu)
                HUD_Panel_Draw(HUD_PANEL(QUICKMENU));
+       HUD_Panel_Draw(HUD_PANEL(SCOREBOARD));
 
-       if (scoreboard_active || intermission == 2)
+       if (intermission == 2)
                HUD_Reset();
 
        HUD_Configure_PostDraw();
index b269312d8871ceb2212ea6fd8beba1f15d28779d..5087fa526929a086937b16d0dadb3463739045a1 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 
 bool HUD_Radar_Clickable();
 void HUD_Radar_Mouse();
@@ -22,14 +22,13 @@ REGISTER_REGISTRY(hud_panels)
 #define HUD_PANEL(NAME) HUD_PANEL_##NAME
 
 // draw the background/borders
-#define HUD_Panel_DrawBg(theAlpha) MACRO_BEGIN { \
+#define HUD_Panel_DrawBg() MACRO_BEGIN { \
        if(panel.current_panel_bg != "0" && panel.current_panel_bg != "") \
                draw_BorderPicture( \
                        HUD_Shift(panel_pos - '1 1 0' * panel_bg_border), \
                        panel.current_panel_bg, \
                        HUD_Scale(panel_size + '1 1 0' * 2 * panel_bg_border), \
-                       panel_bg_color, \
-                       panel_bg_alpha * theAlpha, \
+                       panel_bg_color, panel_bg_alpha, \
                        HUD_Scale('1 1 0' * (panel_bg_border/BORDER_MULTIPLIER)) \
                ); \
 } MACRO_END
@@ -182,12 +181,13 @@ const int PANEL_SHOW_NEVER    = 0x00;
 const int PANEL_SHOW_MAINGAME = 0x01;
 const int PANEL_SHOW_MINIGAME = 0x02;
 const int PANEL_SHOW_MAPVOTE  = 0x04;
+const int PANEL_SHOW_WITH_SB  = 0x08;
 const int PANEL_SHOW_ALWAYS   = 0xff;
-bool HUD_Panel_CheckFlags(int showflags);
 
 .int panel_configflags;
-const int PANEL_CONFIG_NO    = 0x00;
-const int PANEL_CONFIG_MAIN  = 0x01;
+const int PANEL_CONFIG_NO        = 0x00;
+const int PANEL_CONFIG_MAIN      = 0x01;
+const int PANEL_CONFIG_CANBEOFF  = 0x02; // panel can be disabled (if disabled it's displayed with a low alpha)
 
 
 // prev_* vars contain the health/armor at the previous FRAME
@@ -204,31 +204,31 @@ int prev_p_health, prev_p_armor;
 
 void HUD_ItemsTime();
 
-REGISTER_HUD_PANEL(WEAPONS,         HUD_Weapons,        weapons,        PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(AMMO,            HUD_Ammo,           ammo,           PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(POWERUPS,        HUD_Powerups,       powerups,       PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(HEALTHARMOR,     HUD_HealthArmor,    healtharmor,    PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(NOTIFY,          HUD_Notify,         notify,         PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
-REGISTER_HUD_PANEL(TIMER,           HUD_Timer,          timer,          PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
-REGISTER_HUD_PANEL(RADAR,           HUD_Radar,          radar,          PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(SCORE,           HUD_Score,          score,          PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
-REGISTER_HUD_PANEL(RACETIMER,       HUD_RaceTimer,      racetimer,      PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(VOTE,            HUD_Vote,           vote,           PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS  )
-REGISTER_HUD_PANEL(MODICONS,        HUD_ModIcons,       modicons,       PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(PRESSEDKEYS,     HUD_PressedKeys,    pressedkeys,    PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(CHAT,            HUD_Chat,           chat,           PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS  )
-REGISTER_HUD_PANEL(ENGINEINFO,      HUD_EngineInfo,     engineinfo,     PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS  )
-REGISTER_HUD_PANEL(INFOMESSAGES,    HUD_InfoMessages,   infomessages,   PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(PHYSICS,         HUD_Physics,        physics,        PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(CENTERPRINT,     HUD_CenterPrint,    centerprint,    PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(MINIGAME_BOARD,  HUD_MinigameBoard,  minigameboard,  PANEL_CONFIG_NO  , PANEL_SHOW_MINIGAME)
-REGISTER_HUD_PANEL(MINIGAME_STATUS, HUD_MinigameStatus, minigamestatus, PANEL_CONFIG_NO  , PANEL_SHOW_MINIGAME)
-REGISTER_HUD_PANEL(MINIGAME_HELP,   HUD_MinigameHelp,   minigamehelp,   PANEL_CONFIG_NO  , PANEL_SHOW_MINIGAME)
-REGISTER_HUD_PANEL(MINIGAME_MENU,   HUD_MinigameMenu,   minigamemenu,   PANEL_CONFIG_NO  , PANEL_SHOW_ALWAYS  )
-REGISTER_HUD_PANEL(MAPVOTE,         MapVote_Draw,       mapvote,        PANEL_CONFIG_NO  , PANEL_SHOW_MAPVOTE )
-REGISTER_HUD_PANEL(ITEMSTIME,       HUD_ItemsTime,      itemstime,      PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(QUICKMENU,       HUD_QuickMenu,      quickmenu,      PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(SCOREBOARD,      Scoreboard_Draw,    scoreboard,     PANEL_CONFIG_NO  , PANEL_SHOW_ALWAYS  )
+REGISTER_HUD_PANEL(WEAPONS,         HUD_Weapons,        weapons,        PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                                                ) // WEAPONS
+REGISTER_HUD_PANEL(AMMO,            HUD_Ammo,           ammo,           PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                                                ) // AMMO
+REGISTER_HUD_PANEL(POWERUPS,        HUD_Powerups,       powerups,       PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                                                ) // POWERUPS
+REGISTER_HUD_PANEL(HEALTHARMOR,     HUD_HealthArmor,    healtharmor,    PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                                                ) // HEALTHARMOR
+REGISTER_HUD_PANEL(NOTIFY,          HUD_Notify,         notify,         PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME | PANEL_SHOW_MINIGAME                                          ) // NOTIFY
+REGISTER_HUD_PANEL(TIMER,           HUD_Timer,          timer,          PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME | PANEL_SHOW_MINIGAME                      | PANEL_SHOW_WITH_SB) // TIMER
+REGISTER_HUD_PANEL(RADAR,           HUD_Radar,          radar,          PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                                                ) // RADAR
+REGISTER_HUD_PANEL(SCORE,           HUD_Score,          score,          PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME | PANEL_SHOW_MINIGAME                                          ) // SCORE
+REGISTER_HUD_PANEL(RACETIMER,       HUD_RaceTimer,      racetimer,      PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                                                ) // RACETIMER
+REGISTER_HUD_PANEL(VOTE,            HUD_Vote,           vote,           PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME | PANEL_SHOW_MINIGAME | PANEL_SHOW_MAPVOTE | PANEL_SHOW_WITH_SB) // VOTE
+REGISTER_HUD_PANEL(MODICONS,        HUD_ModIcons,       modicons,       PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                            | PANEL_SHOW_WITH_SB) // MODICONS
+REGISTER_HUD_PANEL(PRESSEDKEYS,     HUD_PressedKeys,    pressedkeys,    PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                                                ) // PRESSEDKEYS
+REGISTER_HUD_PANEL(CHAT,            HUD_Chat,           chat,           PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME | PANEL_SHOW_MINIGAME | PANEL_SHOW_MAPVOTE | PANEL_SHOW_WITH_SB) // CHAT
+REGISTER_HUD_PANEL(ENGINEINFO,      HUD_EngineInfo,     engineinfo,     PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME | PANEL_SHOW_MINIGAME | PANEL_SHOW_MAPVOTE | PANEL_SHOW_WITH_SB) // ENGINEINFO
+REGISTER_HUD_PANEL(INFOMESSAGES,    HUD_InfoMessages,   infomessages,   PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                                                ) // INFOMESSAGES
+REGISTER_HUD_PANEL(PHYSICS,         HUD_Physics,        physics,        PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                                                ) // PHYSICS
+REGISTER_HUD_PANEL(CENTERPRINT,     HUD_CenterPrint,    centerprint,    PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                            | PANEL_SHOW_WITH_SB) // CENTERPRINT
+REGISTER_HUD_PANEL(MINIGAME_BOARD,  HUD_MinigameBoard,  minigameboard,  PANEL_CONFIG_NO                          ,                       PANEL_SHOW_MINIGAME                      | PANEL_SHOW_WITH_SB) // MINIGAME_BOARD
+REGISTER_HUD_PANEL(MINIGAME_STATUS, HUD_MinigameStatus, minigamestatus, PANEL_CONFIG_NO                          ,                       PANEL_SHOW_MINIGAME                      | PANEL_SHOW_WITH_SB) // MINIGAME_STATUS
+REGISTER_HUD_PANEL(MINIGAME_HELP,   HUD_MinigameHelp,   minigamehelp,   PANEL_CONFIG_NO                          ,                       PANEL_SHOW_MINIGAME                      | PANEL_SHOW_WITH_SB) // MINIGAME_HELP
+REGISTER_HUD_PANEL(MINIGAME_MENU,   HUD_MinigameMenu,   minigamemenu,   PANEL_CONFIG_NO                          , PANEL_SHOW_MAINGAME | PANEL_SHOW_MINIGAME | PANEL_SHOW_MAPVOTE | PANEL_SHOW_WITH_SB) // MINIGAME_MENU
+REGISTER_HUD_PANEL(MAPVOTE,         MapVote_Draw,       mapvote,        PANEL_CONFIG_NO                          ,                                             PANEL_SHOW_MAPVOTE                     ) // MAPVOTE
+REGISTER_HUD_PANEL(ITEMSTIME,       HUD_ItemsTime,      itemstime,      PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                                                ) // ITEMSTIME
+REGISTER_HUD_PANEL(QUICKMENU,       HUD_QuickMenu,      quickmenu,      PANEL_CONFIG_MAIN                        , PANEL_SHOW_MAINGAME                                                                ) // QUICKMENU
+REGISTER_HUD_PANEL(SCOREBOARD,      Scoreboard_Draw,    scoreboard,     PANEL_CONFIG_NO                          , PANEL_SHOW_MAINGAME | PANEL_SHOW_MINIGAME | PANEL_SHOW_MAPVOTE | PANEL_SHOW_WITH_SB) // SCOREBOARD
 // always add new panels to the end of list
 
 // Because calling lots of functions in QC apparently cuts fps in half on many machines:
@@ -280,9 +280,9 @@ REGISTER_HUD_PANEL(SCOREBOARD,      Scoreboard_Draw,    scoreboard,     PANEL_CO
                        panel_bg_color = autocvar_hud_panel_bg_color;                                                           \
                } else {                                                                                                    \
                        if (panel_bg_color_str == "shirt") {                                                                    \
-                               panel_bg_color = colormapPaletteColor(floor(stof(getplayerkeyvalue(current_player, "colors")) / 16), 0); \
+                               panel_bg_color = colormapPaletteColor(floor(entcs_GetClientColors(current_player) / 16), 0); \
                        } else if (panel_bg_color_str == "pants") {                                                             \
-                               panel_bg_color = colormapPaletteColor(stof(getplayerkeyvalue(current_player, "colors")) % 16, 1); \
+                               panel_bg_color = colormapPaletteColor(entcs_GetClientColors(current_player) % 16, 1); \
                        } else {                                                                                                \
                                panel_bg_color = stov(panel_bg_color_str);                                                          \
                        }                                                                                                       \
@@ -366,9 +366,9 @@ REGISTER_HUD_PANEL(SCOREBOARD,      Scoreboard_Draw,    scoreboard,     PANEL_CO
 } MACRO_END
 
 // NOTE: in hud_configure mode cvars must be reloaded every frame
-#define HUD_Panel_UpdateCvars() MACRO_BEGIN {                                                                       \
+float panel_fade_alpha;
+#define HUD_Panel_LoadCvars() MACRO_BEGIN { \
        if (panel.update_time <= time) {                                                                                \
-               if (autocvar__hud_configure) panel_enabled = cvar(strcat("hud_panel_", panel.panel_name));                  \
                panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos")));                              \
                panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size")));                            \
                HUD_Panel_ScalePosSize();                                                                                   \
@@ -392,8 +392,8 @@ REGISTER_HUD_PANEL(SCOREBOARD,      Scoreboard_Draw,    scoreboard,     PANEL_CO
                if (hud_configure_menu_open == 2 && panel == highlightedPanel) {                                                       \
                        HUD_Panel_UpdatePosSize_ForMenu();                                                                      \
                } else {                                                                                                    \
-                       panel_bg_alpha *= hud_fade_alpha;                                                                       \
-                       panel_fg_alpha *= hud_fade_alpha;                                                                       \
+                       panel_bg_alpha *= hud_fade_alpha * panel_fade_alpha;                                                                       \
+                       panel_fg_alpha *= hud_fade_alpha * panel_fade_alpha;                                                                       \
                }                                                                                                           \
                panel.current_panel_pos = panel_pos;                                                                        \
                panel.current_panel_size = panel_size;                                                                      \
@@ -405,17 +405,21 @@ REGISTER_HUD_PANEL(SCOREBOARD,      Scoreboard_Draw,    scoreboard,     PANEL_CO
        } else {                                                                                                        \
                panel_pos = panel.current_panel_pos;                                                                        \
                panel_size = panel.current_panel_size;                                                                      \
-               panel_bg_alpha = panel.current_panel_bg_alpha * hud_fade_alpha;                                             \
+               panel_bg_alpha = panel.current_panel_bg_alpha * hud_fade_alpha * panel_fade_alpha;                                             \
                panel_bg_border = panel.current_panel_bg_border;                                                            \
                panel_bg_color = panel.current_panel_bg_color;                                                              \
                panel_bg_color_team = panel.current_panel_bg_color_team;                                                    \
                panel_bg_padding = panel.current_panel_bg_padding;                                                          \
-               panel_fg_alpha = panel.current_panel_fg_alpha * hud_fade_alpha;                                             \
+               panel_fg_alpha = panel.current_panel_fg_alpha * hud_fade_alpha * panel_fade_alpha;                                             \
        }                                                                                                               \
 } MACRO_END
 
+#define Hud_Panel_GetPanelEnabled() \
+       panel_enabled = ((panel.panel_configflags & PANEL_CONFIG_CANBEOFF) \
+                                       ? cvar(strcat("hud_panel_", panel.panel_name)) : true)
+
 #define HUD_Panel_UpdatePosSize() MACRO_BEGIN {                                                                     \
-       panel_enabled = cvar(strcat("hud_panel_", panel.panel_name));                                                   \
+       Hud_Panel_GetPanelEnabled(); \
        panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos")));                                  \
        panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size")));                                \
        HUD_Panel_ScalePosSize();                                                                                       \
index 654d49ba8c60f5ce9f59b3eb40bd2b24877d28fa..f2b23e39256217b9f33019b51c2e94bdd1e8b59a 100644 (file)
@@ -848,7 +848,10 @@ LABEL(find_tab_panel)
                        return true;
 
                if (highlightedPanel)
-                       cvar_set(strcat("hud_panel_", highlightedPanel.panel_name), ftos(!cvar(strcat("hud_panel_", highlightedPanel.panel_name))));
+               {
+                       if(panel.panel_configflags & PANEL_CONFIG_CANBEOFF)
+                               cvar_set(strcat("hud_panel_", highlightedPanel.panel_name), ftos(!cvar(strcat("hud_panel_", highlightedPanel.panel_name))));
+               }
                else
                        cvar_set(strcat("hud_dock"), (autocvar_hud_dock == "") ? "dock" : "");
        }
@@ -1108,12 +1111,7 @@ void HUD_Panel_Mouse()
                return;
 
        if (!autocvar_hud_cursormode)
-       {
-               mousepos = mousepos + getmousepos() * autocvar_menu_mouse_speed;
-
-               mousepos.x = bound(0, mousepos.x, vid_conwidth);
-               mousepos.y = bound(0, mousepos.y, vid_conheight);
-       }
+               update_mousepos();
 
        if(mouseClicked)
        {
diff --git a/qcsrc/client/hud/panel.qc b/qcsrc/client/hud/panel.qc
new file mode 100644 (file)
index 0000000..558f320
--- /dev/null
@@ -0,0 +1 @@
+#include "panel.qh"
index d495fdee7670c8874ee45388484abd996092624c..7a95752132c43f3764da1a067db10667ba87c4bd 100644 (file)
@@ -15,7 +15,7 @@
 #include <client/hud/panel/racetimer.qc>
 #include <client/hud/panel/radar.qc>
 #include <client/hud/panel/score.qc>
+#include <client/hud/panel/scoreboard.qc>
 #include <client/hud/panel/timer.qc>
 #include <client/hud/panel/vote.qc>
 #include <client/hud/panel/weapons.qc>
-#include <client/hud/panel/scoreboard.qc>
index fa9b755309da1b4e2b90810e32179230189bd5b9..c24b5c0002876d29d4beca731325ca828004c4e3 100644 (file)
@@ -15,7 +15,7 @@
 #include <client/hud/panel/racetimer.qh>
 #include <client/hud/panel/radar.qh>
 #include <client/hud/panel/score.qh>
+#include <client/hud/panel/scoreboard.qh>
 #include <client/hud/panel/timer.qh>
 #include <client/hud/panel/vote.qh>
 #include <client/hud/panel/weapons.qh>
-#include <client/hud/panel/scoreboard.qh>
index bd3ccd068160d9130db8f308fe28548a4c092dad..e299d1416ea1485da0cd4dee153aa1afc835dd4f 100644 (file)
@@ -104,7 +104,7 @@ void HUD_Ammo()
                        return;
        }
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
 
        draw_beginBoldFont();
 
@@ -116,7 +116,7 @@ void HUD_Ammo()
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        if(panel_bg_padding)
        {
                pos += '1 1 0' * panel_bg_padding;
index 6db88c68b39ee50fce1f8acce9c778465a3223ae..71919d2fb094d48f6c0967de3b4a53cd39ffc453 100644 (file)
@@ -1,2 +1,4 @@
 #pragma once
 #include "../panel.qh"
+
+void DrawNadeProgressBar(vector myPos, vector mySize, float progress, vector color);
index 9dd5f05ff57d6152ba66c05ebdd154a1c2beb79c..5b80690101b089e0e2cd15df07d40aa05bb9356a 100644 (file)
@@ -153,15 +153,7 @@ void HUD_CenterPrint ()
                }
        }
 
-       // this panel fades only when the menu does
-       float hud_fade_alpha_save = hud_fade_alpha;
-       if(hud_configure_menu_open == 1)
-               hud_fade_alpha = 1;
-       else
-               hud_fade_alpha = 1 - autocvar__menu_alpha;
-
-       HUD_Panel_UpdateCvars();
-       hud_fade_alpha = hud_fade_alpha_save;
+       HUD_Panel_LoadCvars();
 
        if ( HUD_Radar_Clickable() )
        {
@@ -189,7 +181,7 @@ void HUD_CenterPrint ()
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
 
        if (!centerprint_showing)
                return;
index 6db88c68b39ee50fce1f8acce9c778465a3223ae..1bec93efa644c684b35340f4973280742b259925 100644 (file)
@@ -1,2 +1,4 @@
 #pragma once
 #include "../panel.qh"
+
+void reset_centerprint_messages();
index 5817142ae609d79ab7359fb5b91a7f4354fa1faa..f3655e940107f101933d096b791a60239b1652f9 100644 (file)
@@ -1,5 +1,7 @@
 #include "chat.qh"
-/** Handle chat as a panel (#12) */
+
+// Chat (#12)
+
 void HUD_Chat()
 {
        if(!autocvar__hud_configure)
@@ -21,7 +23,7 @@ void HUD_Chat()
                }
        }
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
 
        if(intermission == 2)
        {
@@ -56,7 +58,7 @@ void HUD_Chat()
 
        // chat messages don't scale properly since they are displayed directly by the engine
        HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
 
        if(panel_bg_padding)
        {
index 773c751d82680fd826b00ece67514a3891134935..c8b7203eee9cfc240c09ac0556c3709aeaea7b32 100644 (file)
@@ -1,5 +1,6 @@
 #include "engineinfo.qh"
-// Engine info panel (#13)
+
+// Engine info (#13)
 
 float prevfps;
 float prevfps_time;
@@ -18,7 +19,7 @@ void HUD_EngineInfo()
                if(!autocvar_hud_panel_engineinfo) return;
        }
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -27,7 +28,7 @@ void HUD_EngineInfo()
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        if(panel_bg_padding)
        {
                pos += '1 1 0' * panel_bg_padding;
index b56e390b35824802dc07db5bbe60c5f22541ae66..7f5e4c1709c8486a1d591d7703a31ec5c4c963ad 100644 (file)
@@ -2,7 +2,8 @@
 
 #include <common/deathtypes/all.qh>
 
-/** Health/armor (#3) */
+// Health/armor (#3)
+
 void HUD_HealthArmor()
 {
        int armor, health, fuel;
@@ -56,7 +57,7 @@ void HUD_HealthArmor()
                fuel = 20;
        }
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
 
        draw_beginBoldFont();
 
@@ -68,7 +69,7 @@ void HUD_HealthArmor()
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        if(panel_bg_padding)
        {
                pos += '1 1 0' * panel_bg_padding;
index d341b6492efdecf606dffde7229e770113b5f1fe..cd49f09adc769bc0a5cd66450e8178b04a943e4c 100644 (file)
@@ -3,7 +3,7 @@
 #include <common/ent_cs.qh>
 #include <common/mapinfo.qh>
 
-// Info messages panel (#14)
+// Info messages (#14)
 
 float autocvar_hud_panel_infomessages_group0 = 1;
 float autocvar_hud_panel_infomessages_group_fadetime = 0.4;
@@ -60,7 +60,7 @@ void HUD_InfoMessages()
                if(!autocvar_hud_panel_infomessages) return;
        }
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -69,7 +69,7 @@ void HUD_InfoMessages()
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        if(panel_bg_padding)
        {
                pos += '1 1 0' * panel_bg_padding;
index 933528a495f72f20d47b1f76dae0e9c50d05af4c..618f30b1080fa67ae0f4285ee7cc214313bcb0c5 100644 (file)
@@ -1,4 +1,5 @@
 #include "minigame.qh"
-// Minigame
+
+// Minigame (#17, #18, #19, #20)
 
 #include <common/minigames/cl_minigames_hud.qc>
index 2c99485731ebbf1acef68f063a4c4867bb5bb8b5..2a12e81c25e140db54908ee2bc4710aabe7d2f5b 100644 (file)
@@ -4,7 +4,7 @@
 #include <common/ent_cs.qh>
 #include <server/mutators/mutator/gamemode_ctf.qh> // TODO: remove
 
-// Mod icons panel (#10)
+// Mod icons (#10)
 
 bool mod_active; // is there any active mod icon?
 
@@ -758,9 +758,6 @@ void HUD_ModIcons()
                if(!HUD_ModIcons_GameType) return;
        }
 
-       HUD_Panel_UpdateCvars();
-
-       draw_beginBoldFont();
 
        if(mod_active != mod_prev) {
                mod_change = time;
@@ -772,12 +769,19 @@ void HUD_ModIcons()
        else
                mod_alpha = bound(0, 1 - (time - mod_change) * 2, 1);
 
+       //if(mod_alpha <= 0)
+       //      return;
+       panel_fade_alpha *= mod_alpha;
+       HUD_Panel_LoadCvars();
+
+       draw_beginBoldFont();
+
        if (autocvar_hud_panel_modicons_dynamichud)
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       if(mod_alpha)
-               HUD_Panel_DrawBg(mod_alpha);
+
+       HUD_Panel_DrawBg();
 
        if(panel_bg_padding)
        {
index a5e923825a989fc13e9b76b9c077de5b4ce97c31..a49d262a4f9075a9ff615d7435974c6a62e39f20 100644 (file)
@@ -1,5 +1,7 @@
 #include "notify.qh"
-// Notification area (#4)
+
+
+// Notifications (#4)
 
 void HUD_Notify_Push(string icon, string attacker, string victim)
 {
@@ -47,12 +49,13 @@ void HUD_Notify()
                if (!autocvar_hud_panel_notify)
                        return;
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
+
        if (autocvar_hud_panel_notify_dynamichud)
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
 
        if (!autocvar__hud_configure)
                if (notify_count == 0)
index 5fc8c1ca9018cba6b656bf6628d4c59a9edd59bc..6befd1a30a4fe161ea57e386def9eb33f0e2bbfe 100644 (file)
@@ -4,7 +4,7 @@
 #include <common/mapinfo.qh>
 #include <lib/csqcmodel/cl_player.qh>
 
-// Physics panel (#15)
+// Physics (#15)
 
 vector acc_prevspeed;
 float acc_prevtime, acc_avg, top_speed, top_speed_time;
@@ -18,7 +18,7 @@ void HUD_Physics()
                if(autocvar_hud_panel_physics == 3 && !(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
        }
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
 
        draw_beginBoldFont();
 
@@ -26,7 +26,7 @@ void HUD_Physics()
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        if(panel_bg_padding)
        {
                panel_pos += '1 1 0' * panel_bg_padding;
index 7528c2ba2b1a6f89353b6e4cf83116f5ee4a6473..7c454f9f9001ff695115234408f7c571f8d93a25 100644 (file)
@@ -1,6 +1,6 @@
 #include "powerups.qh"
 
-#include <common/items/all.qc>
+#include <common/items/_mod.qh>
 
 // Powerups (#2)
 
@@ -109,12 +109,13 @@ void HUD_Powerups()
                return;
 
        // Draw panel background
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
+
        if (autocvar_hud_panel_powerups_dynamichud)
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
 
        // Set drawing area
        vector pos = panel_pos;
index 6db88c68b39ee50fce1f8acce9c778465a3223ae..3235f8da674507aa494cf3e7e8c29aa132db6bc0 100644 (file)
@@ -1,2 +1,4 @@
 #pragma once
 #include "../panel.qh"
+
+void addPowerupItem(string name, string icon, vector color, float currentTime, float lifeTime);
index d0a4f39fdfd8fc956ce202376af7f5b55f90ac17..abb9ccef9aa56910fae3fd52fb1b3e5699e512ab 100644 (file)
@@ -1,5 +1,8 @@
 #include "pressedkeys.qh"
-/** Draw pressed keys (#11) */
+
+
+// Pressed keys (#11)
+
 void HUD_PressedKeys()
 {
        if(!autocvar__hud_configure)
@@ -8,7 +11,7 @@ void HUD_PressedKeys()
                if(spectatee_status <= 0 && autocvar_hud_panel_pressedkeys < 2) return;
        }
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -17,7 +20,7 @@ void HUD_PressedKeys()
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        if(panel_bg_padding)
        {
                pos += '1 1 0' * panel_bg_padding;
index b2d3588844a00a6044e1cf338e3c1f4257a53c0e..e242ae895881a89d05baf81eb6da4c3197fdf4e7 100644 (file)
@@ -1,10 +1,11 @@
 #include "quickmenu.qh"
-// QuickMenu (#23)
 
 #include <common/ent_cs.qh>
-#include <client/hud/all.qh>
+#include <client/hud/_mod.qh>
 #include <client/mapvoting.qh>
 
+// QuickMenu (#23)
+
 // QUICKMENU_MAXLINES must be <= 10
 const int QUICKMENU_MAXLINES = 10;
 // visible entries are loaded from QuickMenu_Buffer into QuickMenu_Page_* arrays
@@ -495,15 +496,11 @@ void QuickMenu_Mouse()
                return;
        }
 
-       if(!autocvar_hud_cursormode)
-       {
-               mousepos = mousepos + getmousepos() * autocvar_menu_mouse_speed;
-
-               mousepos.x = bound(0, mousepos.x, vid_conwidth);
-               mousepos.y = bound(0, mousepos.y, vid_conheight);
-       }
+       if (!autocvar_hud_cursormode)
+               update_mousepos();
 
-       HUD_Panel_UpdateCvars();
+       panel = HUD_PANEL(QUICKMENU);
+       HUD_Panel_LoadCvars();
 
        if(panel_bg_padding)
        {
@@ -617,10 +614,10 @@ void HUD_QuickMenu()
                }
        }
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
 
        HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
 
        if(panel_bg_padding)
        {
index dd8bbdfec9375597df95e0f755309b21454af9e7..02b631b3000932cbd2ee69f812e5cc8446f2aed1 100644 (file)
@@ -2,7 +2,7 @@
 
 #include <common/mapinfo.qh>
 
-/** Race timer (#8) */
+// Race timer (#6)
 
 // return the string of the onscreen race timer
 string MakeRaceString(int cp, float mytime, float theirtime, float lapdelta, string theirname)
@@ -83,7 +83,7 @@ void HUD_RaceTimer ()
                if(spectatee_status == -1) return;
        }
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
 
        vector pos, mySize;
        pos = panel_pos;
@@ -93,7 +93,7 @@ void HUD_RaceTimer ()
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        if(panel_bg_padding)
        {
                pos += '1 1 0' * panel_bg_padding;
index e935d0cb2b27eba1b395593ca192b412afc13c2e..269d870718e42663a431a3445c984876ff74b4c5 100644 (file)
@@ -137,15 +137,11 @@ void HUD_Radar_Mouse()
                return;
        }
 
-       if(!autocvar_hud_cursormode)
-       {
-               mousepos = mousepos + getmousepos() * autocvar_menu_mouse_speed;
-
-               mousepos_x = bound(0, mousepos_x, vid_conwidth);
-               mousepos_y = bound(0, mousepos_y, vid_conheight);
-       }
+       if (!autocvar_hud_cursormode)
+               update_mousepos();
 
-       HUD_Panel_UpdateCvars();
+       panel = HUD_PANEL(RADAR);
+       HUD_Panel_LoadCvars();
 
 
        panel_size = autocvar_hud_panel_radar_maximized_size;
@@ -197,7 +193,7 @@ void HUD_Radar()
        if ( hud_panel_radar_temp_hidden )
                return;
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
 
        float f = 0;
 
@@ -284,7 +280,7 @@ void HUD_Radar()
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        if(panel_bg_padding)
        {
                pos += '1 1 0' * panel_bg_padding;
@@ -356,7 +352,7 @@ void HUD_Radar()
        IL_EACH(g_radaricons, it.teamradar_icon, {
                if ( hud_panel_radar_mouse )
                if ( it.health >= 0 )
-               if ( it.team == myteam+1 || gametype == MAPINFO_TYPE_RACE || !(serverflags & SERVERFLAG_TEAMPLAY) )
+               if ( it.team == myteam + 1 || gametype == MAPINFO_TYPE_RACE || !teamplay )
                {
                        vector coord = teamradar_texcoord_to_2dcoord(teamradar_3dcoord_to_texcoord(it.origin));
                        if(vdist((mousepos - coord), <, 8))
index cd0d6fa32a887e6448fe25350ff896e1b185275b..4b5df98d19892d237ba925b62f7439afd398eabe 100644 (file)
@@ -140,7 +140,7 @@ void HUD_Score()
                if(spectatee_status == -1 && (gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
        }
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -149,7 +149,7 @@ void HUD_Score()
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        if(panel_bg_padding)
        {
                pos += '1 1 0' * panel_bg_padding;
index 9762384faa0d68aca8ae04dc0bee7ff413717a26..f82c7345ca0c7d3afdc84102cd5a728afa54c6ed 100644 (file)
@@ -8,6 +8,18 @@
 #include <common/stats.qh>
 #include <common/teams.qh>
 
+// Scoreboard (#24)
+
+const int MAX_SBT_FIELDS = MAX_SCORE;
+
+PlayerScoreField sbt_field[MAX_SBT_FIELDS + 1];
+float sbt_field_size[MAX_SBT_FIELDS + 1];
+string sbt_field_title[MAX_SBT_FIELDS + 1];
+int sbt_num_fields;
+
+string autocvar_hud_fontsize;
+string hud_fontsize_str;
+
 float sbt_bg_alpha;
 float sbt_fg_alpha;
 float sbt_fg_alpha_self;
@@ -59,7 +71,7 @@ string TranslateScoresLabel(string l)
                case "captime": return CTX(_("SCO^captime"));
                case "deaths": return CTX(_("SCO^deaths"));
                case "destroyed": return CTX(_("SCO^destroyed"));
-               case "dmg": return CTX(_("SCO^dmg"));
+               case "dmg": return CTX(_("SCO^damage"));
                case "dmgtaken": return CTX(_("SCO^dmgtaken"));
                case "drops": return CTX(_("SCO^drops"));
                case "faults": return CTX(_("SCO^faults"));
@@ -67,8 +79,7 @@ string TranslateScoresLabel(string l)
                case "goals": return CTX(_("SCO^goals"));
                case "kckills": return CTX(_("SCO^kckills"));
                case "kdratio": return CTX(_("SCO^kdratio"));
-               case "k/d": return CTX(_("SCO^k/d"));
-               case "kd": return CTX(_("SCO^kd"));
+               case "kd": return CTX(_("SCO^k/d"));
                case "kdr": return CTX(_("SCO^kdr"));
                case "kills": return CTX(_("SCO^kills"));
                case "laps": return CTX(_("SCO^laps"));
@@ -359,15 +370,12 @@ void Cmd_Scoreboard_SetFields(int argc)
        float missing;
 
        if(!gametype)
-       {
-               // set up a temporary scoreboard layout
-               // no layout can be properly set up until score_info data haven't been received
-               argc = tokenizebyseparator("0 1 ping pl name | score", " ");
-               ps_primary = SP_SCORE;
-               ps_secondary = SP_SCORE;
-               scores_label(ps_primary) = strzone("score");
-               scores_flags(ps_primary) = SFL_ALLOW_HIDE;
-       }
+               return; // do nothing, we don't know gametype and scores yet
+
+       // sbt_fields uses strunzone on the titles!
+       if(!sbt_field_title[0])
+               for(i = 0; i < MAX_SBT_FIELDS; ++i)
+                       sbt_field_title[i] = strzone("(null)");
 
        // TODO: re enable with gametype dependant cvars?
        if(argc < 3) // no arguments provided
@@ -434,13 +442,13 @@ void Cmd_Scoreboard_SetFields(int argc)
                {
                        case "ping": sbt_field[sbt_num_fields] = SP_PING; break;
                        case "pl": sbt_field[sbt_num_fields] = SP_PL; break;
-                       case "kd": case "kdr": case "kdratio": case "k/d": sbt_field[sbt_num_fields] = SP_KDRATIO; break;
+                       case "kd": case "kdr": case "kdratio": sbt_field[sbt_num_fields] = SP_KDRATIO; break;
                        case "sum": case "diff": case "k-d": sbt_field[sbt_num_fields] = SP_SUM; break;
                        case "name": case "nick": sbt_field[sbt_num_fields] = SP_NAME; have_name = true; break;
                        case "|": sbt_field[sbt_num_fields] = SP_SEPARATOR; have_separator = true; break;
                        case "elo": sbt_field[sbt_num_fields] = SP_ELO; break;
-                       case "dmg": sbt_field[sbt_num_fields] = SP_DMG; break;
-                       case "dmgtaken": sbt_field[sbt_num_fields] = SP_DMGTAKEN; break;
+                       case "dmg": case "damage": sbt_field[sbt_num_fields] = SP_DMG; break;
+                       case "dmgtaken": case "damagetaken": sbt_field[sbt_num_fields] = SP_DMGTAKEN; break;
                        default:
                        {
                                FOREACH(Scores, true, {
@@ -553,9 +561,6 @@ string sbt_field_icon2;
 vector sbt_field_icon0_rgb;
 vector sbt_field_icon1_rgb;
 vector sbt_field_icon2_rgb;
-float sbt_field_icon0_alpha;
-float sbt_field_icon1_alpha;
-float sbt_field_icon2_alpha;
 string Scoreboard_GetField(entity pl, PlayerScoreField field)
 {
        float tmp, num, denom;
@@ -568,9 +573,6 @@ string Scoreboard_GetField(entity pl, PlayerScoreField field)
        sbt_field_icon0_rgb = '1 1 1';
        sbt_field_icon1_rgb = '1 1 1';
        sbt_field_icon2_rgb = '1 1 1';
-       sbt_field_icon0_alpha = 1;
-       sbt_field_icon1_alpha = 1;
-       sbt_field_icon2_alpha = 1;
        switch(field)
        {
                case SP_PING:
@@ -605,7 +607,7 @@ string Scoreboard_GetField(entity pl, PlayerScoreField field)
                        }
                        else if(!teamplay)
                        {
-                               f = stof(getplayerkeyvalue(pl.sv_entnum, "colors"));
+                               f = entcs_GetClientColors(pl.sv_entnum);
                                {
                                        sbt_field_icon0 = "gfx/scoreboard/playercolor_base";
                                        sbt_field_icon1 = "gfx/scoreboard/playercolor_shirt";
@@ -658,19 +660,8 @@ string Scoreboard_GetField(entity pl, PlayerScoreField field)
                        }
                }
 
-               case SP_DMG:
-                       num = pl.(scores(SP_DMG));
-                       denom = 1000;
-
-                       str = sprintf("%.1f k", num/denom);
-                       return str;
-
-               case SP_DMGTAKEN:
-                       num = pl.(scores(SP_DMGTAKEN));
-                       denom = 1000;
-
-                       str = sprintf("%.1f k", num/denom);
-                       return str;
+               case SP_DMG: case SP_DMGTAKEN:
+                       return sprintf("%.1f k", pl.(scores(field)) / 1000);
 
                default:
                        tmp = pl.(scores(field));
@@ -695,7 +686,6 @@ string Scoreboard_FixColumnWidth(int i, string str)
     TC(int, i);
        float f;
        vector sz;
-       PlayerScoreField field = sbt_field[i];
 
        sbt_fixcolumnwidth_iconlen = 0;
 
@@ -730,7 +720,7 @@ string Scoreboard_FixColumnWidth(int i, string str)
        else
                sbt_fixcolumnwidth_marginlen = 0;
 
-       if(field == SP_NAME) // name gets all remaining space
+       if(sbt_field[i] == SP_NAME) // name gets all remaining space
        {
                int j;
                float namesize;
@@ -756,6 +746,12 @@ string Scoreboard_FixColumnWidth(int i, string str)
        return str;
 }
 
+void Scoreboard_initFieldSizes()
+{
+       for(int i = 0; i < sbt_num_fields; ++i)
+               sbt_field_size[i] = stringwidth(sbt_field_title[i], false, hud_fontsize);
+}
+
 vector Scoreboard_DrawHeader(vector pos, vector rgb)
 {
        int i;
@@ -815,6 +811,8 @@ void Scoreboard_DrawItem(vector item_pos, vector rgb, entity pl, bool is_self, i
        else if((sbt_highlight) && (!(pl_number % 2)))
                drawfill(h_pos, h_size, rgb, sbt_highlight_alpha, DRAWFLAG_NORMAL);
 
+       float fg_alpha = (is_self ? sbt_fg_alpha_self : sbt_fg_alpha);
+
        vector pos = item_pos;
        pos.x += hud_fontsize.x * 0.5;
        pos.y += (1.25 - 1) / 2 * hud_fontsize.y; // center text vertically
@@ -838,34 +836,19 @@ void Scoreboard_DrawItem(vector item_pos, vector rgb, entity pl, bool is_self, i
 
                if(field == SP_NAME) {
                        tmp.x = sbt_field_size[i] - hud_fontsize.x * sbt_fixcolumnwidth_iconlen - sbt_fixcolumnwidth_marginlen + hud_fontsize.x;
-                       if (is_self)
-                               drawcolorcodedstring(pos - tmp, str, hud_fontsize, sbt_fg_alpha_self, DRAWFLAG_NORMAL);
-                       else
-                               drawcolorcodedstring(pos - tmp, str, hud_fontsize, sbt_fg_alpha, DRAWFLAG_NORMAL);
+                       drawcolorcodedstring(pos - tmp, str, hud_fontsize, fg_alpha, DRAWFLAG_NORMAL);
                } else {
                        tmp.x = sbt_fixcolumnwidth_len + hud_fontsize.x;
-                       if (is_self)
-                               drawstring(pos - tmp, str, hud_fontsize, sbt_field_rgb, sbt_fg_alpha_self, DRAWFLAG_NORMAL);
-                       else
-                               drawstring(pos - tmp, str, hud_fontsize, sbt_field_rgb, sbt_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring(pos - tmp, str, hud_fontsize, sbt_field_rgb, fg_alpha, DRAWFLAG_NORMAL);
                }
 
                tmp.x = sbt_field_size[i] + hud_fontsize.x;
                if(sbt_field_icon0 != "")
-                       if (is_self)
-                               drawpic(pos - tmp, sbt_field_icon0, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon0_alpha * sbt_fg_alpha_self, DRAWFLAG_NORMAL);
-                       else
-                               drawpic(pos - tmp, sbt_field_icon0, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon0_alpha * sbt_fg_alpha, DRAWFLAG_NORMAL);
+                       drawpic(pos - tmp, sbt_field_icon0, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, fg_alpha, DRAWFLAG_NORMAL);
                if(sbt_field_icon1 != "")
-                       if (is_self)
-                               drawpic(pos - tmp, sbt_field_icon1, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon1_alpha * sbt_fg_alpha_self, DRAWFLAG_NORMAL);
-                       else
-                               drawpic(pos - tmp, sbt_field_icon1, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon1_alpha * sbt_fg_alpha, DRAWFLAG_NORMAL);
+                       drawpic(pos - tmp, sbt_field_icon1, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, fg_alpha, DRAWFLAG_NORMAL);
                if(sbt_field_icon2 != "")
-                       if (is_self)
-                               drawpic(pos - tmp, sbt_field_icon2, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon2_rgb, sbt_field_icon2_alpha * sbt_fg_alpha_self, DRAWFLAG_NORMAL);
-                       else
-                               drawpic(pos - tmp, sbt_field_icon2, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon2_rgb, sbt_field_icon2_alpha * sbt_fg_alpha, DRAWFLAG_NORMAL);
+                       drawpic(pos - tmp, sbt_field_icon2, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon2_rgb, fg_alpha, DRAWFLAG_NORMAL);
        }
 
        if(sbt_field[i] == SP_SEPARATOR)
@@ -887,34 +870,19 @@ void Scoreboard_DrawItem(vector item_pos, vector rgb, entity pl, bool is_self, i
 
                        if(field == SP_NAME) {
                                tmp.x = sbt_fixcolumnwidth_len; // left or right aligned? let's put it right...
-                               if(is_self)
-                                       drawcolorcodedstring(pos - tmp, str, hud_fontsize, sbt_fg_alpha_self, DRAWFLAG_NORMAL);
-                               else
-                                       drawcolorcodedstring(pos - tmp, str, hud_fontsize, sbt_fg_alpha, DRAWFLAG_NORMAL);
+                               drawcolorcodedstring(pos - tmp, str, hud_fontsize, fg_alpha, DRAWFLAG_NORMAL);
                        } else {
                                tmp.x = sbt_fixcolumnwidth_len;
-                               if(is_self)
-                                       drawstring(pos - tmp, str, hud_fontsize, sbt_field_rgb, sbt_fg_alpha_self, DRAWFLAG_NORMAL);
-                               else
-                                       drawstring(pos - tmp, str, hud_fontsize, sbt_field_rgb, sbt_fg_alpha, DRAWFLAG_NORMAL);
+                               drawstring(pos - tmp, str, hud_fontsize, sbt_field_rgb, fg_alpha, DRAWFLAG_NORMAL);
                        }
 
                        tmp.x = sbt_field_size[i];
                        if(sbt_field_icon0 != "")
-                               if (is_self)
-                                       drawpic(pos - tmp, sbt_field_icon0, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon0_alpha * sbt_fg_alpha_self, DRAWFLAG_NORMAL);
-                               else
-                                       drawpic(pos - tmp, sbt_field_icon0, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon0_alpha * sbt_fg_alpha, DRAWFLAG_NORMAL);
+                               drawpic(pos - tmp, sbt_field_icon0, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, fg_alpha, DRAWFLAG_NORMAL);
                        if(sbt_field_icon1 != "")
-                               if (is_self)
-                                       drawpic(pos - tmp, sbt_field_icon1, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon1_alpha * sbt_fg_alpha_self, DRAWFLAG_NORMAL);
-                               else
-                                       drawpic(pos - tmp, sbt_field_icon1, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, sbt_field_icon1_alpha * sbt_fg_alpha, DRAWFLAG_NORMAL);
+                               drawpic(pos - tmp, sbt_field_icon1, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon1_rgb, fg_alpha, DRAWFLAG_NORMAL);
                        if(sbt_field_icon2 != "")
-                               if (is_self)
-                                       drawpic(pos - tmp, sbt_field_icon2, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon2_rgb, sbt_field_icon2_alpha * sbt_fg_alpha_self, DRAWFLAG_NORMAL);
-                               else
-                                       drawpic(pos - tmp, sbt_field_icon2, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon2_rgb, sbt_field_icon2_alpha * sbt_fg_alpha, DRAWFLAG_NORMAL);
+                               drawpic(pos - tmp, sbt_field_icon2, eY * hud_fontsize.y + eX * hud_fontsize.x * sbt_fixcolumnwidth_iconlen, sbt_field_icon2_rgb, fg_alpha, DRAWFLAG_NORMAL);
                        pos.x -= sbt_field_size[i] + hud_fontsize.x;
                }
        }
@@ -930,7 +898,7 @@ vector Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
        panel_pos = pos;
        panel_size.y = 1.25 * hud_fontsize.y * (1 + max(1, tm.team_size));
        panel_size.y += panel_bg_padding * 2;
-       HUD_Panel_DrawBg(scoreboard_fade_alpha);
+       HUD_Panel_DrawBg();
 
        vector end_pos = panel_pos + eY * (panel_size.y + hud_fontsize.y);
        if(panel.current_panel_bg != "0")
@@ -1009,23 +977,30 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
        WepSet weapons_stat = WepSet_GetFromStat();
        WepSet weapons_inmap = WepSet_GetFromStat_InMap();
        int disownedcnt = 0;
+       int nHidden = 0;
        FOREACH(Weapons, it != WEP_Null, {
                int weapon_stats = weapon_accuracy[i - WEP_FIRST];
 
                WepSet set = it.m_wepset;
-               if (weapon_stats < 0 && !(weapons_stat & set || weapons_inmap & set))
-                       ++disownedcnt;
+               if (weapon_stats < 0)
+               {
+                       if (!(weapons_stat & set) && (it.spawnflags & WEP_FLAG_HIDDEN || it.spawnflags & WEP_FLAG_MUTATORBLOCKED))
+                               nHidden += 1;
+                       else if (!(weapons_stat & set || weapons_inmap & set))
+                               ++disownedcnt;
+               }
        });
 
-       int weapon_cnt = (Weapons_COUNT - 1) - disownedcnt;
+       int weapon_cnt = (Weapons_COUNT - 1) - disownedcnt - nHidden;
        if (weapon_cnt <= 0) return pos;
 
        int rows = 1;
-       if (autocvar_hud_panel_scoreboard_accuracy_doublerows && weapon_cnt >= floor((Weapons_COUNT - 1) * 0.5))
+       if (autocvar_hud_panel_scoreboard_accuracy_doublerows && weapon_cnt >= floor((Weapons_COUNT - nHidden - 1) * 0.5))
                rows = 2;
        int columnns = ceil(weapon_cnt / rows);
 
-       float height = 40;
+       float weapon_height = 29;
+       float height = hud_fontsize.y + weapon_height;
 
        drawstring(pos + eX * panel_bg_padding, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
        pos.y += 1.25 * hud_fontsize.y;
@@ -1035,7 +1010,7 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
        panel_pos = pos;
        panel_size.y = height * rows;
        panel_size.y += panel_bg_padding * 2;
-       HUD_Panel_DrawBg(scoreboard_fade_alpha);
+       HUD_Panel_DrawBg();
 
        vector end_pos = panel_pos + eY * (panel_size.y + hud_fontsize.y);
        if(panel.current_panel_bg != "0")
@@ -1050,8 +1025,6 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
        pos = panel_pos;
        vector tmp = panel_size;
 
-       float fontsize = height * 1/3;
-       float weapon_height = height * 2/3;
        float weapon_width = tmp.x / columnns / rows;
 
        if (sbt_bg_alpha)
@@ -1066,7 +1039,7 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
 
                // row highlighting
                for (int i = 0; i < rows; ++i)
-                       drawfill(pos + eY * weapon_height + eY * height * i, eX * tmp.x + eY * fontsize, rgb, sbt_highlight_alpha, DRAWFLAG_NORMAL);
+                       drawfill(pos + eY * weapon_height + eY * height * i, eX * tmp.x + eY * hud_fontsize.y, rgb, sbt_highlight_alpha, DRAWFLAG_NORMAL);
        }
 
        average_accuracy = 0;
@@ -1107,12 +1080,12 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
                        s = sprintf("%d%%", weapon_stats * 100);
 
                        float padding;
-                       padding = (weapon_width - stringwidth(s, false, eX * fontsize)) / 2; // center the accuracy value
+                       padding = (weapon_width - stringwidth(s, false, hud_fontsize)) / 2; // center the accuracy value
 
                        if(!autocvar_hud_panel_scoreboard_accuracy_nocolors)
                                rgb = Accuracy_GetColor(weapon_stats);
 
-                       drawstring(tmpos + eX * padding + eY * weapon_height, s, '1 1 0' * fontsize, rgb, sbt_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring(tmpos + eX * padding + eY * weapon_height, s, hud_fontsize, rgb, sbt_fg_alpha, DRAWFLAG_NORMAL);
                }
                tmpos.x += weapon_width * rows;
                pos.x += weapon_width * rows;
@@ -1176,7 +1149,7 @@ vector Scoreboard_MapStats_Draw(vector pos, vector rgb, vector bg_size) {
        panel_pos = pos;
        panel_size.y = hud_fontsize.y * rows;
        panel_size.y += panel_bg_padding * 2;
-       HUD_Panel_DrawBg(scoreboard_fade_alpha);
+       HUD_Panel_DrawBg();
 
        vector end_pos = panel_pos + eY * (panel_size.y + hud_fontsize.y);
        if(panel.current_panel_bg != "0")
@@ -1235,7 +1208,7 @@ vector Scoreboard_Rankings_Draw(vector pos, entity pl, vector rgb, vector bg_siz
        panel_pos = pos;
        panel_size.y = 1.25 * hud_fontsize.y * RANKINGS_RECEIVED_CNT;
        panel_size.y += panel_bg_padding * 2;
-       HUD_Panel_DrawBg(scoreboard_fade_alpha);
+       HUD_Panel_DrawBg();
 
        vector end_pos = panel_pos + eY * (panel_size.y + hud_fontsize.y);
        if(panel.current_panel_bg != "0")
@@ -1281,6 +1254,8 @@ void Scoreboard_Draw()
 {
        if(!autocvar__hud_configure)
        {
+               if(!hud_draw_maximized) return;
+
                // frametime checks allow to toggle the scoreboard even when the game is paused
                if(scoreboard_active) {
                        if(hud_configure_menu_open == 1)
@@ -1290,6 +1265,14 @@ void Scoreboard_Draw()
                                scoreboard_fade_alpha = min(1, scoreboard_fade_alpha + frametime * scoreboard_fadeinspeed);
                        else
                                scoreboard_fade_alpha = 1;
+                       if(hud_fontsize_str != autocvar_hud_fontsize)
+                       {
+                               hud_fontsize = HUD_GetFontsize("hud_fontsize");
+                               Scoreboard_initFieldSizes();
+                               if(hud_fontsize_str)
+                                       strunzone(hud_fontsize_str);
+                               hud_fontsize_str = strzone(autocvar_hud_fontsize);
+                       }
                }
                else {
                        float scoreboard_fadeoutspeed = autocvar_hud_panel_scoreboard_fadeoutspeed;
@@ -1310,12 +1293,10 @@ void Scoreboard_Draw()
        else
                HUD_Scale_Disable();
 
-       float hud_fade_alpha_save = hud_fade_alpha;
-       if(hud_configure_menu_open == 1)
-               hud_fade_alpha = 1;
-       else
-               hud_fade_alpha = scoreboard_fade_alpha * (1 - autocvar__menu_alpha);
-       HUD_Panel_UpdateCvars();
+       if(scoreboard_fade_alpha <= 0)
+               return;
+       panel_fade_alpha *= scoreboard_fade_alpha;
+       HUD_Panel_LoadCvars();
 
        sbt_bg_alpha = autocvar_hud_panel_scoreboard_table_bg_alpha * panel_fg_alpha;
        sbt_highlight = autocvar_hud_panel_scoreboard_table_highlight;
@@ -1324,8 +1305,6 @@ void Scoreboard_Draw()
        sbt_fg_alpha = autocvar_hud_panel_scoreboard_table_fg_alpha * panel_fg_alpha;
        sbt_fg_alpha_self = autocvar_hud_panel_scoreboard_table_fg_alpha_self * panel_fg_alpha;
 
-       hud_fade_alpha = hud_fade_alpha_save;
-
        // don't overlap with con_notify
        if(!autocvar__hud_configure)
                panel_pos.y = max((autocvar_con_notify * autocvar_con_notifysize), panel_pos.y);
index 5a7194a45849ee7967f97e2a9694fccaf3b97c0c..fab0392dc08938d19dd27046faf608e9f1241931 100644 (file)
@@ -1,4 +1,7 @@
 #include "timer.qh"
+
+// Timer (#5)
+
 void HUD_Timer()
 {
        if(!autocvar__hud_configure)
@@ -6,7 +9,7 @@ void HUD_Timer()
                if(!autocvar_hud_panel_timer) return;
        }
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
 
        draw_beginBoldFont();
 
@@ -18,7 +21,7 @@ void HUD_Timer()
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        if(panel_bg_padding)
        {
                pos += '1 1 0' * panel_bg_padding;
@@ -26,7 +29,7 @@ void HUD_Timer()
        }
 
        string timer;
-       float timelimit, elapsedTime, timeleft, minutesLeft;
+       float timelimit, timeleft, minutesLeft;
 
        timelimit = STAT(TIMELIMIT);
 
@@ -47,21 +50,20 @@ void HUD_Timer()
        }
 
        vector timer_color;
-       if(minutesLeft >= 5 || warmup_stage || timelimit == 0) //don't use red or yellow in warmup or when there is no timelimit
+       if(gameover_time || minutesLeft >= 5 || warmup_stage || timelimit == 0)
                timer_color = '1 1 1'; //white
        else if(minutesLeft >= 1)
                timer_color = '1 1 0'; //yellow
        else
                timer_color = '1 0 0'; //red
 
-       if (autocvar_hud_panel_timer_increment || (!warmup_stage && timelimit == 0) || (warmup_stage && warmup_timeleft <= 0)) {
-               if (time < STAT(GAMESTARTTIME)) {
-                       //while restart is still active, show 00:00
-                       timer = seconds_tostring(0);
-               } else {
-                       elapsedTime = floor(time - STAT(GAMESTARTTIME));
-                       timer = seconds_tostring(elapsedTime);
-               }
+       if (gameover_time) {
+               timer = seconds_tostring(max(0, floor(gameover_time - STAT(GAMESTARTTIME))));
+       } else if (autocvar_hud_panel_timer_increment || (!warmup_stage && timelimit == 0) || (warmup_stage && warmup_timeleft <= 0)) {
+               if (time < STAT(GAMESTARTTIME))
+                       timer = seconds_tostring(0); //while restart is still active, show 00:00
+               else
+                       timer = seconds_tostring(floor(time - STAT(GAMESTARTTIME)));
        } else {
                if(warmup_stage)
                        timer = seconds_tostring(warmup_timeleft);
index a732b0c5ee7a2073c8a32e00ca054633fcb2c320..1c2ea03bc8ec3a11708c7921a976855b6e4ee9fb 100644 (file)
@@ -2,17 +2,17 @@
 
 #include <common/mapinfo.qh>
 
-/** Vote window (#9) */
+// Vote (#9)
+
 void HUD_Vote()
 {
        if(autocvar_cl_allow_uid2name == -1 && (gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || (serverflags & SERVERFLAG_PLAYERSTATS)))
        {
                // this dialog gets overriden by the uid2name menu dialog, if it exists
                // TODO remove this client side uid2name dialog in the next release
-               if(autocvar__menu_alpha)
-                       hud_fade_alpha = 0;
-               else
+               if(!autocvar__menu_alpha)
                        uid2name_dialog = 0;
+
                if (!uid2name_dialog)
                        localcmd("menu_cmd directmenu Uid2Name\n");
 
@@ -33,14 +33,12 @@ void HUD_Vote()
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_vote) return;
-
-               panel_fg_alpha = autocvar_hud_panel_fg_alpha;
-               panel_bg_alpha_str = autocvar_hud_panel_vote_bg_alpha;
-
-               if(panel_bg_alpha_str == "") {
-                       panel_bg_alpha_str = ftos(autocvar_hud_panel_bg_alpha);
-               }
-               panel_bg_alpha = stof(panel_bg_alpha_str);
+               /*
+               if(cvar("hud_panel_vote_test")) {
+                       if(vote_called_vote) strunzone(vote_called_vote); vote_called_vote = strzone("^1test the vote panel");
+                       vote_active = true; vote_yescount = 3; vote_nocount = 2; vote_needed = 4;
+               } else vote_active = false;
+               */
        }
        else
        {
@@ -61,10 +59,18 @@ void HUD_Vote()
        else
                vote_alpha = bound(0, 1 - (time - vote_change) * 2, 1);
 
-       if(!vote_alpha)
+       a = vote_alpha * (vote_highlighted ? autocvar_hud_panel_vote_alreadyvoted_alpha : 1);
+       if(a <= 0)
                return;
-
-       HUD_Panel_UpdateCvars();
+       //panel_fade_alpha *= a;
+       // nothing can hide this panel, not even the menu
+       float hud_fade_alpha_save = hud_fade_alpha;
+       if(uid2name_dialog && autocvar__menu_alpha)
+               hud_fade_alpha = 0;
+       else
+               hud_fade_alpha = a;
+       HUD_Panel_LoadCvars();
+       hud_fade_alpha = hud_fade_alpha_save;
 
        if(uid2name_dialog)
        {
@@ -76,13 +82,11 @@ void HUD_Vote()
        pos = panel_pos;
        mySize = panel_size;
 
-       a = vote_alpha * (vote_highlighted ? autocvar_hud_panel_vote_alreadyvoted_alpha : 1);
        if (autocvar_hud_panel_vote_dynamichud)
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(a);
-       a = panel_fg_alpha * a;
+       HUD_Panel_DrawBg();
 
        if(panel_bg_padding)
        {
@@ -111,42 +115,44 @@ void HUD_Vote()
        s = _("A vote has been called for:");
        if(uid2name_dialog)
                s = _("Allow servers to store and display your name?");
-       drawstring_aspect(pos, s, eX * mySize.x + eY * (2/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+       drawstring_aspect(pos, s, eX * mySize.x + eY * (2/8) * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
        s = textShortenToWidth(vote_called_vote, mySize.x, '1 1 0' * mySize.y * (1/8), stringwidth_colors);
        if(autocvar__hud_configure)
                s = _("^1Configure the HUD");
-       drawcolorcodedstring_aspect(pos + eY * (2/8) * mySize.y, s, eX * mySize.x + eY * (1.75/8) * mySize.y, a, DRAWFLAG_NORMAL);
+       drawcolorcodedstring_aspect(pos + eY * (2/8) * mySize.y, s, eX * mySize.x + eY * (1.75/8) * mySize.y, panel_fg_alpha, DRAWFLAG_NORMAL);
 
        // print the yes/no counts
        s = sprintf("^2%s ^7(%d)", getcommandkey_forcename(_("Yes"), "vyes"), vote_yescount);
-       drawcolorcodedstring_aspect(pos + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, a, DRAWFLAG_NORMAL);
+       drawcolorcodedstring_aspect(pos + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, panel_fg_alpha, DRAWFLAG_NORMAL);
        s = sprintf("^1%s ^7(%d)", getcommandkey_forcename(_("No"), "vno"), vote_nocount);
-       drawcolorcodedstring_aspect(pos + eX * 0.5 * mySize.x + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, a, DRAWFLAG_NORMAL);
+       drawcolorcodedstring_aspect(pos + eX * 0.5 * mySize.x + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, panel_fg_alpha, DRAWFLAG_NORMAL);
 
+       pos.y += (5/8) * mySize.y;
+       vector tmp_size = eX * mySize.x + eY * (3/8) * mySize.y;
        // draw the progress bar backgrounds
-       drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_back", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+       drawpic_skin(pos, "voteprogress_back", tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 
        // draw the highlights
        if(vote_highlighted == 1) {
                drawsetcliparea(pos.x, pos.y, mySize.x * 0.5, mySize.y);
-               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_voted", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+               drawpic_skin(pos, "voteprogress_voted", tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
        }
        else if(vote_highlighted == -1) {
                drawsetcliparea(pos.x + 0.5 * mySize.x, pos.y, mySize.x * 0.5, mySize.y);
-               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_voted", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+               drawpic_skin(pos, "voteprogress_voted", tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
        }
 
        // draw the progress bars
        if(vote_yescount && vote_needed)
        {
                drawsetcliparea(pos.x, pos.y, mySize.x * 0.5 * (vote_yescount/vote_needed), mySize.y);
-               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_prog", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+               drawpic_skin(pos, "voteprogress_prog", tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
        }
 
        if(vote_nocount && vote_needed)
        {
                drawsetcliparea(pos.x + mySize.x - mySize.x * 0.5 * (vote_nocount/vote_needed), pos.y, mySize.x * 0.5, mySize.y);
-               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_prog", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+               drawpic_skin(pos, "voteprogress_prog", tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
        }
 
        drawresetcliparea();
index fe2aefc60d1c3fe5f123c49386a235ccb3cc2b8b..db25d532a016f938e31a04045ac54e1886f03617 100644 (file)
@@ -1,5 +1,7 @@
 #include "weapons.qh"
-// Weapon icons (#0)
+
+
+// Weapons (#0)
 
 entity weaponorder[Weapons_MAX];
 void weaponorder_swap(int i, int j, entity pass)
@@ -23,7 +25,7 @@ int weaponorder_cmp(int i, int j, entity pass)
        int nHidden = 0; \
        FOREACH(Weapons, it != WEP_Null, { \
                if (weapons_stat & WepSet_FromWeapon(it)) continue; \
-               if (it.spawnflags & WEP_FLAG_MUTATORBLOCKED) nHidden += 1; \
+               if (it.spawnflags & WEP_FLAG_HIDDEN || it.spawnflags & WEP_FLAG_MUTATORBLOCKED) nHidden += 1; \
        }); \
        vector table_size = HUD_GetTableSize_BestItemAR((Weapons_COUNT - 1) - nHidden, panel_size, aspect); \
        columns = table_size.x; \
@@ -81,7 +83,7 @@ void HUD_Weapons()
        }
 
        // update generic hud functions
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
 
        // figure out weapon order (how the weapons are sorted) // TODO make this configurable
        if(weaponorder_bypriority != autocvar_cl_weaponpriority || !weaponorder[0])
@@ -152,7 +154,7 @@ void HUD_Weapons()
                if(autocvar__hud_configure)
                {
                        if(hud_configure_menu_open != 2)
-                               HUD_Panel_DrawBg(1); // also draw the bg of the entire panel
+                               HUD_Panel_DrawBg(); // also draw the bg of the entire panel
                }
 
                // do we own this weapon?
@@ -314,7 +316,7 @@ void HUD_Weapons()
                HUD_Scale_Enable();
        else
                HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
 
        if(center.x == -1)
                return; // panel has gone off screen
index c5e47237b17b995a16d29cf06a5d5c9964c769df..9bcfd4e7a9c58571bbafdba76dfb5b247a1ba230 100644 (file)
@@ -1,7 +1,7 @@
 #include "main.qh"
 
 #include <common/effects/qc/all.qh>
-#include "hud/all.qh"
+#include "hud/_mod.qh"
 #include "mapvoting.qh"
 #include "mutators/events.qh"
 #include "hud/panel/scoreboard.qh"
@@ -11,7 +11,7 @@
 #include "wall.qh"
 #include "weapons/projectile.qh"
 #include <common/deathtypes/all.qh>
-#include <common/items/all.qh>
+#include <common/items/_mod.qh>
 #include <common/mapinfo.qh>
 #include <common/minigames/cl_minigames.qh>
 #include <common/minigames/cl_minigames_hud.qh>
@@ -132,12 +132,6 @@ void CSQC_Init()
 
        gametype = NULL;
 
-       // sbt_fields uses strunzone on the titles!
-       for(int i = 0; i < MAX_SBT_FIELDS; ++i)
-               sbt_field_title[i] = strzone("(null)");
-
-       Cmd_Scoreboard_SetFields(0);
-
        postinit = false;
 
        calledhooks = 0;
@@ -714,7 +708,7 @@ NET_HANDLE(ENT_CLIENT_SPAWNPOINT, bool is_new)
                }*/
                if(autocvar_cl_spawn_point_particles)
                {
-                       if((serverflags & SERVERFLAG_TEAMPLAY))
+                       if(teamplay)
                        {
                                switch(teamnum)
                                {
@@ -950,6 +944,7 @@ NET_HANDLE(ENT_CLIENT_SCORES_INFO, bool isnew)
 {
        make_pure(this);
        gametype = ReadRegistered(Gametypes);
+       teamplay = _MapInfo_GetTeamPlayBool(gametype);
        HUD_ModIcons_SetFunc();
        FOREACH(Scores, true, {
                if (scores_label(it)) strunzone(scores_label(it));
index e736d9d4463732353e3f4608dce038424a9bcd5f..0a096f962a8f9b7f90c446bc864e6b4403abd6ea 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 #include <common/constants.qh>
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 
 // --------------------------------------------------------------------------
 // MENU Functionality
@@ -40,13 +40,6 @@ void LoadMenuSkinValues();
 // --------------------------------------------------------------------------
 // Scoreboard stuff
 
-const int MAX_SBT_FIELDS = MAX_SCORE;
-
-PlayerScoreField sbt_field[MAX_SBT_FIELDS + 1];
-float sbt_field_size[MAX_SBT_FIELDS + 1];
-string sbt_field_title[MAX_SBT_FIELDS + 1];
-int sbt_num_fields;
-
 vector hud_fontsize;
 
 float RANKINGS_RECEIVED_CNT;
index 57daed8eb1f396840e247ff82c778a1793566a62..7b07b680057196bb325bda90f4d4dd03fd8866a3 100644 (file)
@@ -1,6 +1,6 @@
 #include "mapvoting.qh"
 
-#include "hud/all.qh"
+#include "hud/_mod.qh"
 #include "hud/panel/scoreboard.qh"
 
 #include <common/mapinfo.qh>
@@ -24,7 +24,6 @@ float mv_timeout;
 float mv_top2_time;
 float mv_top2_alpha;
 
-vector mv_mousepos;
 int mv_selection;
 int mv_columns;
 int mv_mouse_selection;
@@ -84,6 +83,7 @@ void GameTypeVote_DrawGameTypeItem(vector pos, float maxh, float tsize, string g
                alpha = mv_top2_alpha; // Fade away if not one of the top 2 choice
        else
                alpha = 1; // Normal, full alpha
+       alpha *= panel_fg_alpha;
 
        // Bounding box details
        float rect_margin = hud_fontsize.y / 2;
@@ -101,14 +101,14 @@ void GameTypeVote_DrawGameTypeItem(vector pos, float maxh, float tsize, string g
        // Highlight selected item
        if(id == mv_selection && (mv_flags[id] & GTV_AVAILABLE))
        {
-               drawfill(rect_pos, rect_size, '1 1 1', 0.1, DRAWFLAG_NORMAL);
+               drawfill(rect_pos, rect_size, '1 1 1', 0.1 * panel_fg_alpha, DRAWFLAG_NORMAL);
        }
 
        // Highlight current vote
        vector rgb = MapVote_RGB(id);
        if(id == mv_ownvote)
        {
-               drawfill(rect_pos, rect_size, rgb, 0.1*alpha, DRAWFLAG_NORMAL);
+               drawfill(rect_pos, rect_size, rgb, 0.1 * alpha, DRAWFLAG_NORMAL);
                drawborderlines(autocvar_hud_panel_mapvote_highlight_border, rect_pos, rect_size, rgb, alpha, DRAWFLAG_NORMAL);
        }
 
@@ -230,16 +230,17 @@ void MapVote_DrawMapItem(vector pos, float isize, float tsize, string map, strin
                theAlpha = mv_top2_alpha;
        else
                theAlpha = 1;
+       theAlpha *= panel_fg_alpha;
 
        // Highlight selected item
        if(id == mv_selection && (mv_flags[id] & GTV_AVAILABLE))
-               drawfill(rect_pos, rect_size, '1 1 1', 0.1, DRAWFLAG_NORMAL);
+               drawfill(rect_pos, rect_size, '1 1 1', 0.1 * panel_fg_alpha, DRAWFLAG_NORMAL);
 
        // Highlight current vote
        vector rgb = MapVote_RGB(id);
        if(id == mv_ownvote)
        {
-               drawfill(rect_pos, rect_size, rgb, 0.1*theAlpha, DRAWFLAG_NORMAL);
+               drawfill(rect_pos, rect_size, rgb, 0.1 * theAlpha, DRAWFLAG_NORMAL);
                drawborderlines(autocvar_hud_panel_mapvote_highlight_border, rect_pos, rect_size, rgb, theAlpha, DRAWFLAG_NORMAL);
        }
 
@@ -272,7 +273,7 @@ void MapVote_DrawAbstain(vector pos, float isize, float tsize, float _count, int
        text_size = stringwidth(label, false, hud_fontsize);
 
        pos.x -= text_size*0.5;
-       drawstring(pos, label, hud_fontsize, rgb, 1, DRAWFLAG_NORMAL);
+       drawstring(pos, label, hud_fontsize, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
 }
 
 vector MapVote_GridVec(vector gridspec, int i, int m)
@@ -295,10 +296,10 @@ float MapVote_Selection(vector topleft, vector cellsize, float rows, float colum
        for (r = 0; r < rows; ++r)
                for (c = 0; c < columns; ++c)
                {
-                       if (mv_mousepos.x >= topleft.x + cellsize.x *  c &&
-                               mv_mousepos.x <= topleft.x + cellsize.x * (c + 1) &&
-                               mv_mousepos.y >= topleft.y + cellsize.y *  r &&
-                               mv_mousepos.y <= topleft.y + cellsize.y * (r + 1))
+                       if (mousepos.x >= topleft.x + cellsize.x *  c &&
+                               mousepos.x <= topleft.x + cellsize.x * (c + 1) &&
+                               mousepos.y >= topleft.y + cellsize.y *  r &&
+                               mousepos.y <= topleft.y + cellsize.y * (r + 1))
                        {
                                mv_mouse_selection = r * columns + c;
                                break;
@@ -332,15 +333,14 @@ void MapVote_Draw()
        if(!mv_active)
                return;
 
+       HUD_Panel_LoadCvars();
+
        if (!autocvar_hud_cursormode)
        {
-               vector mpos = mv_mousepos + getmousepos();
-               mpos.x = bound(0, mpos.x, vid_conwidth);
-               mpos.y = bound(0, mpos.y, vid_conheight);
-
-               if ( mpos.x != mv_mousepos.x || mpos.y != mv_mousepos.y )
+               vector mpos = mousepos;
+               update_mousepos();
+               if (mpos.x != mousepos.x || mpos.y != mousepos.y)
                        mv_selection_keyboard = 0;
-               mv_mousepos = mpos;
        }
 
        center = (vid_conwidth - 1)/2;
@@ -364,14 +364,14 @@ void MapVote_Draw()
 
        map = ((gametypevote) ? _("Decide the gametype") : _("Vote for a map"));
        pos.x = center - stringwidth(map, false, hud_fontsize * 2) * 0.5;
-       drawstring(pos, map, hud_fontsize * 2, '1 1 1', 1, DRAWFLAG_NORMAL);
+       drawstring(pos, map, hud_fontsize * 2, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
        pos.y += hud_fontsize.y * 2;
 
        if( mapvote_chosenmap != "" )
        {
                pos.y += hud_fontsize.y * 0.25;
                pos.x = center - stringwidth(mapvote_chosenmap, false, hud_fontsize * 1.5) * 0.5;
-               drawstring(pos, mapvote_chosenmap, hud_fontsize * 1.5, '1 1 1', 1, DRAWFLAG_NORMAL);
+               drawstring(pos, mapvote_chosenmap, hud_fontsize * 1.5, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
                pos.y += hud_fontsize.y * 1.5;
        }
        pos.y += hud_fontsize.y * 0.5;
@@ -381,12 +381,10 @@ void MapVote_Draw()
        i = ceil(max(0, mv_timeout - time));
        map = sprintf(_("%d seconds left"), i);
        pos.x = center - stringwidth(map, false, hud_fontsize * 1.5) * 0.5;
-       drawstring(pos, map, hud_fontsize * 1.5, '0 1 0', 1, DRAWFLAG_NORMAL);
+       drawstring(pos, map, hud_fontsize * 1.5, '0 1 0', panel_fg_alpha, DRAWFLAG_NORMAL);
        pos.y += hud_fontsize.y * 1.5;
        pos.y += hud_fontsize.y * 0.5;
 
-       HUD_Panel_UpdateCvars();
-
        // base for multi-column stuff...
        pos.y += hud_fontsize.y;
        pos.x = xmin;
@@ -440,7 +438,7 @@ void MapVote_Draw()
        panel_pos.y = pos.y;
        panel_size.x = xmax - xmin;
        panel_size.y = ymax - ymin;
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
 
        if(panel_bg_padding)
        {
@@ -486,7 +484,7 @@ void MapVote_Draw()
                MapVote_DrawAbstain(pos, dist.x, xmax - xmin, tmp, i);
        }
 
-       draw_cursor_normal(mv_mousepos, '1 1 1', 1 - autocvar__menu_alpha);
+       draw_cursor_normal(mousepos, '1 1 1', panel_fg_alpha);
 }
 
 void Cmd_MapVote_MapDownload(int argc)
@@ -649,8 +647,8 @@ void GameTypeVote_ReadOption(int i)
 void MapVote_Init()
 {
        mv_active = 1;
-       if(autocvar_hud_cursormode) { setcursormode(1); }
-       else { mv_mousepos = '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight; }
+       if(autocvar_hud_cursormode) setcursormode(1);
+       else mousepos = '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight;
        mv_selection = -1;
        mv_selection_keyboard = 0;
 
@@ -786,8 +784,8 @@ float MapVote_InputEvent(int bInputType, float nPrimary, float nSecondary)
 
        if(bInputType == 3)
        {
-               mv_mousepos.x = nPrimary;
-               mv_mousepos.y = nSecondary;
+               mousepos.x = nPrimary;
+               mousepos.y = nSecondary;
                mv_selection_keyboard = 0;
                return true;
        }
index 01b0ee3cb440c09d4b00503500f9a2561d697fd7..0e88cd5a51043107b2d2246e79351151dccc538e 100644 (file)
@@ -1,8 +1,8 @@
 #include "miscfunctions.qh"
 
-#include "hud/all.qh"
+#include "hud/_mod.qh"
 
-#include <common/command/generic.qh>
+#include <common/command/_mod.qh>
 
 #include <common/teams.qh>
 
@@ -350,6 +350,13 @@ void drawcolorcodedstring_aspect_expanding(vector pos, string text, vector sz, f
        drawcolorcodedstring_expanding(pos, text, '1 1 0' * sz.y, theAlpha, drawflag, fadelerp);
 }
 
+void update_mousepos()
+{
+       mousepos += getmousepos() * autocvar_menu_mouse_speed;
+       mousepos.x = bound(0, mousepos.x, vid_conwidth);
+       mousepos.y = bound(0, mousepos.y, vid_conheight);
+}
+
 // this draws the triangles of a model DIRECTLY. Don't expect high performance, really...
 float PolyDrawModelSurface(entity e, float i_s)
 {
index 1f8790481f1a8d88a0193d9971d8b65b2dcbad4b..9d792f60cd62ad3335e5531e8c48c483a16dc199 100644 (file)
@@ -187,6 +187,8 @@ void drawcolorcodedstring_expanding(vector position, string text, vector theScal
 
 void drawcolorcodedstring_aspect_expanding(vector pos, string text, vector sz, float theAlpha, float drawflag, float fadelerp);
 
+void update_mousepos();
+
 // this draws the triangles of a model DIRECTLY. Don't expect high performance, really...
 float PolyDrawModelSurface(entity e, float i_s);
 void PolyDrawModel(entity e);
index 98fb4815c1ce28cc699a429537ea75c2643b4487..3dfd4f78974b38371a435762abe7eaa35f611c85 100644 (file)
@@ -1 +1,2 @@
 // generated file; do not modify
+#include <client/mutators/events.qc>
index 98fb4815c1ce28cc699a429537ea75c2643b4487..b54ee489cf0909a46d34a92a313124cd27d80619 100644 (file)
@@ -1 +1,2 @@
 // generated file; do not modify
+#include <client/mutators/events.qh>
diff --git a/qcsrc/client/mutators/events.qc b/qcsrc/client/mutators/events.qc
new file mode 100644 (file)
index 0000000..c2dbb70
--- /dev/null
@@ -0,0 +1 @@
+#include "events.qh"
index 48579ecbb3018b131203cbe08ea5231a427f560f..327df77c25fd6583f6fe7365bf931f61cc52400d 100644 (file)
@@ -1,32 +1,11 @@
 #include <lib/_all.inc>
 
 #if XONOTIC
-
-#include "_all.qh"
-
-#include "../client/_mod.inc"
-#include "commands/_mod.inc"
-#include "hud/_mod.inc"
-#include "mutators/_mod.inc"
-#include "weapons/_mod.inc"
-
-#include <common/_all.inc>
-#include <common/effects/qc/all.qc>
-
-#include <lib/csqcmodel/cl_model.qc>
-#include <lib/csqcmodel/cl_player.qc>
-#include <lib/csqcmodel/interpolate.qc>
-
-#include <lib/warpzone/anglestransform.qc>
-#include <lib/warpzone/common.qc>
-#include <lib/warpzone/client.qc>
-#include <lib/warpzone/server.qc>
-#include <lib/warpzone/util_server.qc>
-
+#include <client/_all.inc>
 #endif
 
-#include <ecs/_lib.inc>
+#include <ecs/_mod.inc>
 
-#if BUILD_MOD
-#include "../../mod/client/progs.inc"
+#ifdef BUILD_MOD
+#include <mod/client/progs.inc>
 #endif
index 165b033fb3558c8197e6e758b4dd4b39f3156f4e..75ef40521ea443504048bb7669c161db0f671fda 100644 (file)
@@ -1,6 +1,6 @@
 #include "shownames.qh"
 
-#include "hud/all.qh"
+#include "hud/_mod.qh"
 
 #include <common/ent_cs.qh>
 #include <common/constants.qh>
index ab14cd3bf38d04a89d48ead845339bcbf582e271..9c4544bba08c0afce4ed04c14b8546d979da4d70 100644 (file)
@@ -1,6 +1,6 @@
 #include "teamradar.qh"
 
-#include "hud/all.qh"
+#include "hud/_mod.qh"
 
 #include <common/mutators/mutator/waypoints/all.qh>
 
index db6df4dadfc972de58f3c8f2c4effbd1f563c883..cd156e65ec7b3989e0afc6ce1d8a08faa4c4aa12 100644 (file)
@@ -1,7 +1,7 @@
 #include "view.qh"
 
 #include "announcer.qh"
-#include "hud/all.qh"
+#include "hud/_mod.qh"
 #include "mapvoting.qh"
 #include "shownames.qh"
 #include "hud/panel/scoreboard.qh"
 #include <common/constants.qh>
 #include <common/debug.qh>
 #include <common/mapinfo.qh>
-#include <common/gamemodes/all.qh>
+#include <common/gamemodes/_mod.qh>
 #include <common/physics/player.qh>
 #include <common/stats.qh>
 #include <common/triggers/target/music.qh>
 #include <common/teams.qh>
 
 #include <common/vehicles/all.qh>
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 #include <common/viewloc.qh>
 #include <common/minigames/cl_minigames.qh>
 #include <common/minigames/cl_minigames_hud.qh>
@@ -293,7 +293,7 @@ void viewmodel_draw(entity this)
        else if (wasinvehicle) a = 1;
        wasinvehicle = invehicle;
        Weapon wep = activeweapon;
-       int c = stof(getplayerkeyvalue(current_player, "colors"));
+       int c = entcs_GetClientColors(current_player);
        vector g = weaponentity_glowmod(wep, c);
        entity me = CSQCModel_server2csqc(player_localentnum - 1);
        int fx = ((me.csqcmodel_effects & EFMASK_CHEAP)
@@ -980,7 +980,7 @@ void HUD_Crosshair(entity this)
                                v = wcross_origin - wcross_oldorigin;
                                v.x /= vid_conwidth;
                                v.y /= vid_conheight;
-                               if(vlen(v) > 0.01)
+                               if(vdist(v, >, 0.01))
                                        shottype = SHOTTYPE_HITOBSTRUCTION;
                        }
                        if(!autocvar_crosshair_hittest_showimpact)
@@ -1322,6 +1322,13 @@ void HUD_Crosshair(entity this)
 
 void HUD_Draw(entity this)
 {
+       // if we don't know gametype and scores yet avoid drawing the scoreboard
+       // also in the very first frames, player state may be inconsistent so avoid drawing the hud at all
+       // e.g. since initial player's health is 0 hud would display the hud_damage effect,
+       // cl_deathscoreboard would show the scoreboard and so on
+       if(!gametype)
+               return;
+
        if(!intermission)
        if (MUTATOR_CALLHOOK(HUD_Draw_overlay))
        {
@@ -1500,9 +1507,10 @@ void CSQC_UpdateView(entity this, float w, float h)
                        }
                }
 
-               if(ons_roundlost)
+               if(ons_roundlost) // TODO: move this junk to a client mutator for onslaught (possible using the WantEventchase hook)
                {
-                       FOREACH_ENTITY_CLASS("onslaught_generator", it.health <= 0, {
+                       IL_EACH(g_onsgenerators, it.health <= 0,
+                       {
                                gen = it;
                                break;
                        });
@@ -1735,6 +1743,9 @@ void CSQC_UpdateView(entity this, float w, float h)
        if(!postinit)
                PostInit();
 
+       if(intermission && !gameover_time)
+               gameover_time = time;
+
        if(intermission && !isdemo() && !(calledhooks & HOOK_END))
        {
                if(calledhooks & HOOK_START)
@@ -1774,13 +1785,6 @@ void CSQC_UpdateView(entity this, float w, float h)
 
        switchweapon = Weapons_from(STAT(SWITCHWEAPON));
 
-       f = (serverflags & SERVERFLAG_TEAMPLAY);
-       if(f != teamplay)
-       {
-               teamplay = f;
-               Scoreboard_InitScores();
-       }
-
        if(last_switchweapon != switchweapon)
        {
                weapontime = time;
index b16c24fb47086179068f433c7b93a057f28836c0..5177c9dfd17320b7a3bc4dfa577639a608637ba8 100644 (file)
@@ -1,6 +1,6 @@
 float autocvar_net_connecttimeout = 30;
 
-#ifndef MENUQC
+#ifdef GAMEQC
 #include "anim.qc"
 #include "animdecide.qc"
 #include "ent_cs.qc"
@@ -19,19 +19,21 @@ float autocvar_net_connecttimeout = 30;
 #include "campaign_setup.qc"
 #endif
 
-#ifndef MENUQC
+#ifdef GAMEQC
 #include "physics/all.inc"
 #include "triggers/include.qc"
 #include "viewloc.qc"
 #endif
 
-#ifndef MENUQC
+#ifdef GAMEQC
 #include "minigames/minigames.qc"
 #endif
 
 #include "debug.qh"
 
-#ifndef MENUQC
+#include "command/_mod.inc"
+
+#ifdef GAMEQC
 #include "deathtypes/all.qc"
 #include "effects/all.qc"
 #include "impulses/all.qc"
@@ -40,8 +42,8 @@ float autocvar_net_connecttimeout = 30;
 #endif
 
 #include "items/_mod.inc"
-    #include "weapons/all.qc"
-        #include "monsters/all.qc"
+    #include "weapons/_all.inc"
+        #include "monsters/_mod.inc"
         #include "turrets/all.qc"
         #include "vehicles/all.qc"
 
index ab389278d16fcd696d850af106c59947b4108da6..b53a9ba0e9cbf6123d7438736785e8206200358a 100644 (file)
@@ -1,6 +1,6 @@
 #include "animdecide.qh"
 
-#include <common/monsters/all.qh>
+#include <common/monsters/_mod.qh>
 
 #if defined(SVQC)
     #include "util.qh"
index a8bbe8e856c430a7fdfaf85e9ab5a4988c96a13d..af81942a2001753c36e9fb1cebdadc6ae283b2bb 100644 (file)
@@ -1,3 +1,4 @@
+#include "campaign_file.qh"
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
diff --git a/qcsrc/common/campaign_file.qh b/qcsrc/common/campaign_file.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 8c20c755c31a33881a6b37933d464b63ab5bb329..258d47f452bef14facee6dc58a693086b05caded 100644 (file)
@@ -1,3 +1,4 @@
+#include "campaign_setup.qh"
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
diff --git a/qcsrc/common/campaign_setup.qh b/qcsrc/common/campaign_setup.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index d2d24f03d901cb0775702698267551e80eabb7d9..e3099980edfca432898b372a6086463f04680b88 100644 (file)
@@ -1,5 +1,5 @@
 // generated file; do not modify
-#include <common/command/all.qc>
 #include <common/command/generic.qc>
 #include <common/command/markup.qc>
+#include <common/command/reg.qc>
 #include <common/command/rpn.qc>
index 440bdcb13460d5486a642803de0604d0a82ba58d..6ca293773c6c51b42551693bd54b1ad397db4d52 100644 (file)
@@ -1,5 +1,5 @@
 // generated file; do not modify
-#include <common/command/all.qh>
 #include <common/command/generic.qh>
 #include <common/command/markup.qh>
+#include <common/command/reg.qh>
 #include <common/command/rpn.qh>
diff --git a/qcsrc/common/command/all.qc b/qcsrc/common/command/all.qc
deleted file mode 100644 (file)
index dc1c044..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "generic.qc"
-#include "markup.qc"
-#include "rpn.qc"
diff --git a/qcsrc/common/command/all.qh b/qcsrc/common/command/all.qh
deleted file mode 100644 (file)
index 15285b9..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-
-#include "command.qh"
-REGISTRY(GENERIC_COMMANDS, BITS(7))
-#define GENERIC_COMMANDS_from(i) _GENERIC_COMMANDS_from(i, NULL)
-REGISTER_REGISTRY(GENERIC_COMMANDS)
-REGISTRY_SORT(GENERIC_COMMANDS)
-
-#define GENERIC_COMMAND(id, description) \
-       CLASS(genericcommand_##id, Command) \
-               ATTRIB(genericcommand_##id, m_name, string, #id); \
-       ATTRIB(genericcommand_##id, m_description, string, description); \
-       ENDCLASS(genericcommand_##id) \
-    REGISTER(GENERIC_COMMANDS, CMD_G, id, m_id, NEW(genericcommand_##id)); \
-       METHOD(genericcommand_##id, m_invokecmd, void(genericcommand_##id this, int request, entity caller, int arguments, string command))
-
-STATIC_INIT(GENERIC_COMMANDS_aliases) {
-       FOREACH(GENERIC_COMMANDS, true, localcmd(sprintf("alias %1$s \"%2$s %1$s ${* ?}\"\n", it.m_name, "qc_cmd_svmenu")));
-}
-
-#include "generic.qh"
-#include "markup.qh"
-#include "rpn.qh"
index 8f3449b3e16cfaef91bcc8b0b0bd47171deb8523..49a9d130989015125f171c6dedfa59561fd7ace2 100644 (file)
@@ -1,11 +1,13 @@
-#include "all.qh"
+#include "generic.qh"
+#include "_mod.qh"
+#include "reg.qh"
 
 #include "markup.qh"
 #include "rpn.qh"
 
 #include "../mapinfo.qh"
 
-#ifndef MENUQC
+#ifdef GAMEQC
        #include "../notifications/all.qh"
 #endif
 
 #endif
 
 #ifdef SVQC
-       #include <server/command/banning.qh>
-       #include <server/command/cmd.qh>
-       #include <server/command/common.qh>
-       #include <server/command/sv_cmd.qh>
+       #include <server/command/_mod.qh>
        #include <common/turrets/config.qh>
        #include <common/weapons/config.qh>
 #endif
@@ -374,7 +373,7 @@ void GenericCommand_restartnotifs(float request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       #ifndef MENUQC
+                       #ifdef GAMEQC
                        int NOTIF_ANNCE_COUNT   = 0; FOREACH(Notifications, it.nent_type == MSG_ANNCE,   { ++NOTIF_ANNCE_COUNT;  });
                        int NOTIF_INFO_COUNT    = 0; FOREACH(Notifications, it.nent_type == MSG_INFO,    { ++NOTIF_INFO_COUNT;   });
                        int NOTIF_CENTER_COUNT  = 0; FOREACH(Notifications, it.nent_type == MSG_CENTER,  { ++NOTIF_CENTER_COUNT; });
index 583c61e5517d89d046869c1d3ca3050714beeff0..95a3b53c54b9950b7b7dc525669c40b583f08895 100644 (file)
@@ -1,5 +1,5 @@
-#include "command.qh"
 #include "markup.qh"
+#include "command.qh"
 
 // =========================================================
 //  Markup chat characters command code, reworked by Samual
diff --git a/qcsrc/common/command/reg.qc b/qcsrc/common/command/reg.qc
new file mode 100644 (file)
index 0000000..c0af5b5
--- /dev/null
@@ -0,0 +1 @@
+#include "reg.qh"
diff --git a/qcsrc/common/command/reg.qh b/qcsrc/common/command/reg.qh
new file mode 100644 (file)
index 0000000..9868e24
--- /dev/null
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "command.qh"
+REGISTRY(GENERIC_COMMANDS, BITS(7))
+#define GENERIC_COMMANDS_from(i) _GENERIC_COMMANDS_from(i, NULL)
+REGISTER_REGISTRY(GENERIC_COMMANDS)
+REGISTRY_SORT(GENERIC_COMMANDS)
+
+#define GENERIC_COMMAND(id, description) \
+       CLASS(genericcommand_##id, Command) \
+               ATTRIB(genericcommand_##id, m_name, string, #id); \
+       ATTRIB(genericcommand_##id, m_description, string, description); \
+       ENDCLASS(genericcommand_##id) \
+    REGISTER(GENERIC_COMMANDS, CMD_G, id, m_id, NEW(genericcommand_##id)); \
+       METHOD(genericcommand_##id, m_invokecmd, void(genericcommand_##id this, int request, entity caller, int arguments, string command))
+
+STATIC_INIT(GENERIC_COMMANDS_aliases) {
+       FOREACH(GENERIC_COMMANDS, true, localcmd(sprintf("alias %1$s \"%2$s %1$s ${* ?}\"\n", it.m_name, "qc_cmd_svmenu")));
+}
index 12bb99d1d3e862b43904298c57627bb1e874b05c..f88bf635ee665b9628f0e69f0a6b1d1d58b430a8 100644 (file)
@@ -1,5 +1,5 @@
-#include "command.qh"
 #include "rpn.qh"
+#include "command.qh"
 
 
 // ========================================
index 6c775560394259816e14622b1584cb2843b34d59..181511cc1a1cb819e4ddf94ea691038647bdfd2f 100644 (file)
@@ -126,7 +126,7 @@ const int SFL_SORT_PRIO_MASK = 12;
  * Score indices
  */
 
-#ifndef MENUQC
+#ifdef GAMEQC
 
 #define IS_INCREASING(x) ( (x) & SFL_LOWER_IS_BETTER )
 #define IS_DECREASING(x) ( !((x) & SFL_LOWER_IS_BETTER) )
@@ -154,10 +154,9 @@ USING(PlayerScoreField, entity);
 REGISTER_SP(END);
 
 REGISTER_SP(PING);
+REGISTER_SP(PL);
 REGISTER_SP(NAME);
 REGISTER_SP(KDRATIO);
-REGISTER_SP(CLRATIO);
-REGISTER_SP(PL);
 REGISTER_SP(SUM);
 
 REGISTER_SP(SEPARATOR);
index 052e00f07c4df4e0548c5c3fdba01b02bceff18c..6d580bd2d69a8b65631a465d0adee730e6bca07d 100644 (file)
@@ -4,7 +4,7 @@
 .entity tag_entity;
 #endif
 
-#ifndef MENUQC
+#ifdef GAMEQC
 .bool debug;
 .int sv_entnum;
 REGISTER_NET_TEMP(net_debug)
@@ -47,7 +47,7 @@ REGISTER_NET_TEMP(net_debug)
        }
 #endif
 
-#ifndef MENUQC
+#ifdef GAMEQC
 /**
  * 0: off
  * 1: on
index 6975259c17783f683e86e5717d0198e1e0106f51..d5dab8cad27418e143cb9aa8bf63f962e061711e 100644 (file)
@@ -1,3 +1,5 @@
 // generated file; do not modify
 #include <common/effects/all.qc>
 #include <common/effects/effectinfo.qc>
+
+#include <common/effects/qc/_mod.inc>
index 3f5ed82198904e347d7ad9850c4fab8eb4e6c8a2..8d6e8ed18c98e59ad7e3943100732bcb6b862932 100644 (file)
@@ -1,3 +1,5 @@
 // generated file; do not modify
 #include <common/effects/all.qh>
 #include <common/effects/effectinfo.qh>
+
+#include <common/effects/qc/_mod.qh>
index cf6d5fca9395a29b8985a1e059522bd1a5f8206e..f662aee7b2a0e4b8d097537308cf96a98f6a1e41 100644 (file)
@@ -1,3 +1,4 @@
+#include "effectinfo.qh"
 #define EFFECTINFO_PARSER(on, MY) \
     on(type,                                        MY(type) \
     ,{ demand(n == 1 && "type");                    MY(type) = strzone(argv(1)); \
diff --git a/qcsrc/common/effects/effectinfo.qh b/qcsrc/common/effects/effectinfo.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index f92df7cd0edba6770769114dba75f8a4d4970fd9..d0befbb7ed04705feb92bb01e63d291011003bed 100644 (file)
@@ -1,3 +1,4 @@
+#include "casings.qh"
 #ifdef SVQC
 void SpawnCasing(vector vel, float randomvel, vector ang, vector avel, float randomavel, int casingtype, entity casingowner, .entity weaponentity);
 #endif
diff --git a/qcsrc/common/effects/qc/casings.qh b/qcsrc/common/effects/qc/casings.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index d17502e81ba99fcf0c11eb49c2182c0a0c4fce1d..71e1e2a7bcdd96dcf3f72629d7e147d4db03aab3 100644 (file)
@@ -1,15 +1,4 @@
-#ifndef DAMAGEEFFECTS_H
-#define DAMAGEEFFECTS_H
-
-#ifdef CSQC
-#include <common/deathtypes/all.qh>
-#include <common/physics/movetypes/movetypes.qh>
-#include <client/mutators/events.qh>
-#include <common/vehicles/all.qh>
-#include <common/weapons/all.qh>
-#endif
-
-#endif
+#include "damageeffects.qh"
 
 #ifdef IMPLEMENTATION
 
diff --git a/qcsrc/common/effects/qc/damageeffects.qh b/qcsrc/common/effects/qc/damageeffects.qh
new file mode 100644 (file)
index 0000000..2a1d587
--- /dev/null
@@ -0,0 +1,9 @@
+#pragma once
+
+#ifdef CSQC
+#include <common/deathtypes/all.qh>
+#include <common/physics/movetypes/movetypes.qh>
+#include <client/mutators/events.qh>
+#include <common/vehicles/all.qh>
+#include <common/weapons/_all.qh>
+#endif
index 573b52f22cc83986e0755f87b76ff44dabdda777..d60b2e8a65892bd33f4d0b285ce00328b2b095a0 100644 (file)
@@ -6,7 +6,7 @@
        #include <common/animdecide.qh>
 
        #ifdef SVQC
-               #include <server/cl_player.qh>
+               #include <server/player.qh>
        #endif
 
        REGISTER_NET_TEMP(globalsound)
index 83a6941213d627dbeca64e0174cc9e662696310e..dd3785b68ea2cf65af3fb5ecc5c77f86c0b102e0 100644 (file)
@@ -5,7 +5,10 @@
 entityclass(Rubble);
 class(Rubble).float creationtime;
 
-void RubbleLimit(string cname, float limit, void(entity) deleteproc)
+IntrusiveList g_rubble;
+STATIC_INIT(g_rubble) { g_rubble = IL_NEW(); }
+
+void RubbleLimit(string cname, int limit, void(entity) deleteproc)
 {
        // remove rubble of the same type if it's at the limit
        // remove multiple rubble if the limit has been decreased
@@ -17,7 +20,7 @@ void RubbleLimit(string cname, float limit, void(entity) deleteproc)
                entity oldest = NULL;
                float oldesttime = 0;
                // compare to all other matching entities
-               FOREACH_ENTITY_CLASS(cname, true,
+               IL_EACH(g_rubble, it.classname == cname,
                {
                        ++c;
                        if(!oldest || oldesttime > it.creationtime)
@@ -41,6 +44,7 @@ entity RubbleNew(string cname)
        entity e = spawn();
        e.classname = cname;
        e.creationtime = time;
+       IL_PUSH(g_rubble, e);
        return e;
 }
 
index 2a7b3f80c485ef413e246028834d20ad38d8156b..17ee08e7cf14937037696112f4a7edf941c2ab4e 100644 (file)
@@ -1,39 +1,53 @@
 #include "ent_cs.qh"
 
-// #define PROP(public, fld, sv, cl)
-#define ENTCS_NETPROPS(PROP) \
-       PROP(true, sv_entnum, \
-       { WriteByte(chan, etof(player) - 1); }, \
-       { this.sv_entnum = ReadByte(); }) \
-    \
-       PROP(false, origin, \
+#define ENTCS_SET_NORMAL(var, x) MACRO_BEGIN \
+       var = x; \
+MACRO_END
+
+/** the engine player name strings are mutable! */
+#define ENTCS_SET_MUTABLE_STRING(var, x) MACRO_BEGIN \
+       if (var) strunzone(var); \
+       var = strzone(x); \
+MACRO_END
+
+// #define PROP(public, fld, set, sv, cl)
+#define ENTCS_NETPROPS(PROP) PROP(false, sv_entnum, ENTCS_SET_NORMAL, {}, {}) /* sentinel */ \
+       PROP(false, origin, ENTCS_SET_NORMAL, \
        { WriteShort(chan, this.origin.x);  WriteShort(chan, this.origin.y); \
          WriteShort(chan, this.origin.z); }, \
        { this.has_sv_origin = true; vector v; v.x = ReadShort(); v.y = ReadShort(); v.z = ReadShort(); setorigin(this, v); }) \
     \
-       PROP(false, angles_y, \
+       PROP(false, angles_y, ENTCS_SET_NORMAL, \
        { WriteByte(chan, this.angles.y / 360 * 256); }, \
        { vector v = '0 0 0'; v.y = ReadByte() / 256 * 360; this.angles = v; }) \
     \
-       PROP(false, health, \
+       PROP(false, health, ENTCS_SET_NORMAL, \
        { WriteByte(chan, bound(0, this.health / 10, 255));  /* FIXME: use a better scale? */ }, \
        { this.healthvalue = ReadByte() * 10; }) \
     \
-       PROP(false, armorvalue, \
+       PROP(false, armorvalue, ENTCS_SET_NORMAL, \
        { WriteByte(chan, bound(0, this.armorvalue / 10, 255));  /* FIXME: use a better scale? */ }, \
        { this.armorvalue = ReadByte() * 10; }) \
     \
-       PROP(true, netname, \
+       PROP(true, netname, ENTCS_SET_MUTABLE_STRING, \
        { WriteString(chan, this.netname); }, \
        { if (this.netname) strunzone(this.netname); this.netname = strzone(ReadString()); }) \
     \
-       PROP(true, model, \
+       PROP(true, model, ENTCS_SET_NORMAL, \
        { WriteString(chan, this.model); }, \
        { if (this.model) strunzone(this.model); this.model = strzone(ReadString()); }) \
     \
-       PROP(true, skin, \
+       PROP(true, skin, ENTCS_SET_NORMAL, \
        { WriteByte(chan, this.skin); }, \
        { this.skin = ReadByte(); }) \
+    \
+    PROP(true, clientcolors, ENTCS_SET_NORMAL, \
+       { WriteByte(chan, this.clientcolors); }, \
+       { this.colormap = ReadByte(); }) \
+    \
+    PROP(true, frags, ENTCS_SET_NORMAL, \
+       { WriteShort(chan, this.frags); }, \
+       { this.frags = ReadShort(); }) \
     \
        /**/
 
        int ENTCS_PUBLICMASK = 0;
        STATIC_INIT(ENTCS_PUBLICMASK)
        {
-               int i = 1;
-               #define X(public, fld, sv, cl) { if (public) ENTCS_PUBLICMASK |= BIT(i); } i += 1;
+               int i = 0;
+               #define X(public, fld, set, sv, cl) { \
+                       if (public) { \
+                               ENTCS_PUBLICMASK |= BIT(i); \
+                       } \
+                       i += 1; \
+               }
                ENTCS_NETPROPS(X);
        #undef X
                if (i >= BITS(16 - 1)) LOG_FATAL("Exceeded ENTCS_NETPROPS limit");
        bool _entcs_send(entity this, entity to, int sf, int chan)
        {
                entity player = this.owner;
-               sf |= BIT(0) | BIT(1);
-               if (IS_PLAYER(to) || to.caplayer)                                  // unless spectating,
-               {
-                       bool same_team = (to == player) || (teamplay && player.team == to.team);
-                       if (!same_team && !radar_showennemies) sf &= ENTCS_PUBLICMASK; // no private updates
-               }
+               sf |= BIT(0); // assume private
+               do {
+                       if (radar_showennemies) break;
+                       if (SAME_TEAM(to, player)) break;
+                       if (!(IS_PLAYER(to) || to.caplayer) && time > game_starttime) break;
+                       sf &= ENTCS_PUBLICMASK; // no private updates
+               } while (0);
                sf |= this.m_forceupdate;
                this.m_forceupdate = 0;
-               bool valid =
-                       time > game_starttime
-                   && (IS_PLAYER(player)          // player must be active
-                   || player == to)               // player is self
-               ;
-               if (!valid) sf = 0;
                if (chan == MSG_ENTITY)
                        WriteHeader(chan, ENT_CLIENT_ENTCS);
                else
                        WriteHeader(chan, CLIENT_ENTCS);
                WriteByte(chan, etof(player) - 1);
                WriteShort(chan, sf);
-               int i = 1;
-               #define X(public, fld, sv, cl) { if (sf & BIT(i)) sv; } i += 1;
+               int i = 0;
+               #define X(public, fld, set, sv, cl) { \
+                       if (sf & BIT(i)) { \
+                               sv; \
+                       } \
+                       i += 1; \
+               }
                ENTCS_NETPROPS(X);
        #undef X
                return true;
        {
                this.nextthink = time + 0.033333333333;  // TODO: increase this to like 0.15 once the client can do smoothing
                entity o = this.owner;
-               int i = 1;
-               #define X(public, fld, sv, cl) \
-                       if (o.fld != this.fld) \
-                       { \
-                               this.fld = o.fld; \
+               int i = 0;
+               #define X(public, fld, set, sv, cl) { \
+                       if (o.fld != this.fld) { \
+                               set(this.fld, o.fld); \
                                this.SendFlags |= BIT(i); \
                        } \
-                       i += 1;
+                       i += 1; \
+               }
                ENTCS_NETPROPS(X);
        #undef X
            setorigin(this, this.origin);  // relink
        {
                int n = ReadByte();
                entity e = entcs_receiver(n);
+               #define X(e) { \
+                       setthink(e, entcs_think); \
+                       entcs_receiver(n, e); \
+               }
                if (e == NULL)
                {
-                       if (this)
+                       if (!this)
                        {
-                               e = this;
+                               // initial = temp
+                               e = new_pure(entcs_receiver);
+                               X(e);
                        }
                        else
                        {
-                               e = new(entcs_receiver);
-                               make_pure(e);
+                               // initial = linked
+                               e = this;
+                               X(e);
                        }
-                       e.sv_entnum = n;
-                       setthink(e, entcs_think);
-                       entcs_receiver(n, e);
                }
-               else if (this && e != this)
+               else if (e != this && this)
                {
-                       this.classname = "entcs_gc";
-                       this.sv_entnum = n;
+                       // upgrade to linked
+                       delete(e);
+                       e = this;
+                       X(e);
                }
-               this = e;
-               InterpolateOrigin_Undo(this);
-               this.sv_entnum = n;
+               #undef X
+               InterpolateOrigin_Undo(e);
+               e.sv_entnum = n;
                int sf = ReadShort();
-               this.has_sv_origin = false;
-               this.m_entcs_private = boolean(sf & BIT(0));
-               int i = 1;
-               #define X(public, fld, sv, cl) { if (sf & BIT(i)) cl; } i += 1;
+               e.has_sv_origin = false;
+               e.m_entcs_private = boolean(sf & BIT(0));
+               int i = 0;
+               #define X(public, fld, set, sv, cl) { \
+                       if (sf & BIT(i)) { \
+                               cl; \
+                       } \
+                       i += 1; \
+               }
                ENTCS_NETPROPS(X);
        #undef X
-               this.iflags |= IFLAG_ORIGIN;
-               InterpolateOrigin_Note(this);
-               getthink(this)(this);
+               e.iflags |= IFLAG_ORIGIN;
+               InterpolateOrigin_Note(e);
+               getthink(e)(e);
                return true;
        }
 
index fdaaab2d57c0f37be4345a824a3892a3fdd90e51..65cdd83d3a71f4f5df325a8e90b727d936cb1300 100644 (file)
@@ -58,10 +58,21 @@ REGISTER_NET_TEMP(CLIENT_ENTCS)
        /**
      * @param i zero indexed player
      */
+    .int frags;
        bool entcs_IsSpectating(int i)
        {
                bool unconnected = !playerslots[i].gotscores;
-               return unconnected || stof(getplayerkeyvalue(i, "frags")) == FRAGS_SPECTATOR;
+               entity e = entcs_receiver(i);
+               return unconnected || ((e) ? e.frags : stof(getplayerkeyvalue(i, "frags"))) == FRAGS_SPECTATOR;
+       }
+
+       /**
+     * @param i zero indexed player
+     */
+       int entcs_GetClientColors(int i)
+       {
+               entity e = entcs_receiver(i);
+               return e ? e.colormap : stof(getplayerkeyvalue(i, "colors"));
        }
 
        /**
@@ -70,7 +81,7 @@ REGISTER_NET_TEMP(CLIENT_ENTCS)
        */
        int entcs_GetTeamColor(int i)
        {
-               return (!teamplay) ? 0 : stof(getplayerkeyvalue(i, "colors")) & 15;
+               return (!teamplay) ? 0 : entcs_GetClientColors(i) & 15;
        }
 
        /**
@@ -97,7 +108,8 @@ REGISTER_NET_TEMP(CLIENT_ENTCS)
        */
        string entcs_GetName(int i)
        {
-               return ColorTranslateRGB(getplayerkeyvalue(i, "name"));
+               entity e = entcs_receiver(i);
+               return ColorTranslateRGB(e ? e.netname : getplayerkeyvalue(i, "name"));
        }
 
     /**
@@ -126,7 +138,7 @@ REGISTER_NET_TEMP(CLIENT_ENTCS)
                       ? '1 1 1'
                           : colormapPaletteColor(((e.colormap >= 1024)
                        ? e.colormap
-                       : stof(getplayerkeyvalue(e.colormap - 1, "colors"))) & 15, true)
+                       : entcs_GetClientColors(e.colormap - 1)) & 15, true)
                ;
        }
 
index 0b779498b186ad5a57ba3373155f79baa6969a22..c3cec69dc5268cddd04a9afb11e422e4bf3b3a71 100644 (file)
@@ -1,2 +1,3 @@
 // generated file; do not modify
-#include <common/gamemodes/all.qc>
+
+#include <common/gamemodes/gamemode/_mod.inc>
index a7b7a54af44b8c2777885d56b7d38a48911ba5e8..685c277b4e18bf7771f2852d40138ad39dc14063 100644 (file)
@@ -1,2 +1,3 @@
 // generated file; do not modify
-#include <common/gamemodes/all.qh>
+
+#include <common/gamemodes/gamemode/_mod.qh>
diff --git a/qcsrc/common/gamemodes/all.inc b/qcsrc/common/gamemodes/all.inc
deleted file mode 100644 (file)
index bcdcd7c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "gamemode/nexball/module.inc"
-#include "gamemode/onslaught/module.inc"
diff --git a/qcsrc/common/gamemodes/all.qc b/qcsrc/common/gamemodes/all.qc
deleted file mode 100644 (file)
index f0fc719..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "all.qh"
-
-#define IMPLEMENTATION
-#include "all.inc"
-#undef IMPLEMENTATION
diff --git a/qcsrc/common/gamemodes/all.qh b/qcsrc/common/gamemodes/all.qh
deleted file mode 100644 (file)
index 62ba616..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef GAMEMODES_ALL_H
-#define GAMEMODES_ALL_H
-
-#include "all.inc"
-
-#endif
index 98fb4815c1ce28cc699a429537ea75c2643b4487..2fc2c404678883117dcd9205365e36317f5e997e 100644 (file)
@@ -1 +1,4 @@
 // generated file; do not modify
+
+#include <common/gamemodes/gamemode/nexball/_mod.inc>
+#include <common/gamemodes/gamemode/onslaught/_mod.inc>
index 98fb4815c1ce28cc699a429537ea75c2643b4487..d79957012609493478bdf9e0a03ea2116fec63c3 100644 (file)
@@ -1 +1,4 @@
 // generated file; do not modify
+
+#include <common/gamemodes/gamemode/nexball/_mod.qh>
+#include <common/gamemodes/gamemode/onslaught/_mod.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/nexball/module.inc b/qcsrc/common/gamemodes/gamemode/nexball/module.inc
deleted file mode 100644 (file)
index 0d80962..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "nexball.qc"
-#include "weapon.qc"
index 0f0ecb471943ff4623627aa9cbcd9206676bf9d5..0054fd63607b1523c5b729382e1fe52c593da6d9 100644 (file)
@@ -1,6 +1,5 @@
 #include "nexball.qh"
 
-#ifdef IMPLEMENTATION
 #ifdef CSQC
 int autocvar_cl_eventchase_nexball = 1;
 
@@ -836,6 +835,7 @@ void W_Nexball_Attack2(entity actor, .entity weaponentity)
        missile.effects = EF_BRIGHTFIELD | EF_LOWPRECISION;
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
+       IL_PUSH(g_bot_dodge, missile);
 
        CSQCProjectile(missile, true, PROJECTILE_ELECTRO, true);
 }
@@ -1157,4 +1157,3 @@ REGISTER_MUTATOR(nb, g_nexball)
 }
 
 #endif
-#endif
index 9dd8042be32ab87f369874e7718ca1e19feb2031..53797d2bc6d245dc7de9ee17abaa5143836a5e31 100644 (file)
@@ -1,5 +1,4 @@
-#ifndef GAMEMODE_NEXBALL_H
-#define GAMEMODE_NEXBALL_H
+#pragma once
 
 #ifdef SVQC
 //EF_BRIGHTFIELD|EF_BRIGHTLIGHT|EF_DIMLIGHT|EF_BLUE|EF_RED|EF_FLAME
@@ -35,4 +34,3 @@ float nb_teams;
 
 .float teamtime;
 #endif
-#endif
index c6aa4be215a21fca52c75cf00388f6a7de730af3..f207263535387422196ff99095a2c5d01e6c8d54 100644 (file)
@@ -1,12 +1 @@
-#ifndef GAMEMODE_NEXBALL_WEAPON_H
-#define GAMEMODE_NEXBALL_WEAPON_H
-
-CLASS(BallStealer, PortoLaunch)
-/* flags     */ ATTRIB(BallStealer, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
-/* impulse   */ ATTRIB(BallStealer, impulse, int, 0);
-/* refname   */ ATTRIB(BallStealer, netname, string, "ballstealer");
-/* wepname   */ ATTRIB(BallStealer, m_name, string, _("Ball Stealer"));
-ENDCLASS(BallStealer)
-REGISTER_WEAPON(NEXBALL, NEW(BallStealer));
-
-#endif
+#include "weapon.qh"
diff --git a/qcsrc/common/gamemodes/gamemode/nexball/weapon.qh b/qcsrc/common/gamemodes/gamemode/nexball/weapon.qh
new file mode 100644 (file)
index 0000000..73b8872
--- /dev/null
@@ -0,0 +1,9 @@
+#pragma once
+
+CLASS(BallStealer, PortoLaunch)
+/* flags     */ ATTRIB(BallStealer, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* impulse   */ ATTRIB(BallStealer, impulse, int, 0);
+/* refname   */ ATTRIB(BallStealer, netname, string, "ballstealer");
+/* wepname   */ ATTRIB(BallStealer, m_name, string, _("Ball Stealer"));
+ENDCLASS(BallStealer)
+REGISTER_WEAPON(NEXBALL, NEW(BallStealer));
index 334eb561ee14fd816cfcd9113f7d9b5c1a9206af..ca8c83c19a08ecb0ba4ef9efb8203e2df13c55dd 100644 (file)
@@ -1,6 +1,19 @@
 // generated file; do not modify
-#include <common/gamemodes/gamemode/onslaught/cl_controlpoint.qc>
-#include <common/gamemodes/gamemode/onslaught/cl_generator.qc>
+#include <common/gamemodes/gamemode/onslaught/controlpoint.qc>
+#ifdef CSQC
+    #include <common/gamemodes/gamemode/onslaught/cl_controlpoint.qc>
+#endif
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/onslaught/sv_controlpoint.qc>
+#endif
+#include <common/gamemodes/gamemode/onslaught/generator.qc>
+#ifdef CSQC
+    #include <common/gamemodes/gamemode/onslaught/cl_generator.qc>
+#endif
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/onslaught/sv_generator.qc>
+#endif
 #include <common/gamemodes/gamemode/onslaught/onslaught.qc>
-#include <common/gamemodes/gamemode/onslaught/sv_controlpoint.qc>
-#include <common/gamemodes/gamemode/onslaught/sv_generator.qc>
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/onslaught/sv_onslaught.qc>
+#endif
index e895495581e4e57bf8d7d4e97bc9b95008a13856..bb95416b310a2206e025398b432ebe699533cd4d 100644 (file)
@@ -1,6 +1,19 @@
 // generated file; do not modify
-#include <common/gamemodes/gamemode/onslaught/cl_controlpoint.qh>
-#include <common/gamemodes/gamemode/onslaught/cl_generator.qh>
+#include <common/gamemodes/gamemode/onslaught/controlpoint.qh>
+#ifdef CSQC
+    #include <common/gamemodes/gamemode/onslaught/cl_controlpoint.qh>
+#endif
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/onslaught/sv_controlpoint.qh>
+#endif
+#include <common/gamemodes/gamemode/onslaught/generator.qh>
+#ifdef CSQC
+    #include <common/gamemodes/gamemode/onslaught/cl_generator.qh>
+#endif
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/onslaught/sv_generator.qh>
+#endif
 #include <common/gamemodes/gamemode/onslaught/onslaught.qh>
-#include <common/gamemodes/gamemode/onslaught/sv_controlpoint.qh>
-#include <common/gamemodes/gamemode/onslaught/sv_generator.qh>
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/onslaught/sv_onslaught.qh>
+#endif
index fb8cb71719a2e4acea5a10718a737eb4f54d50bb..ee348fdbc6244707f53e7b6202aae30cd6392ea7 100644 (file)
@@ -104,7 +104,7 @@ void cpicon_damage(entity this, float hp)
        setsize(this, CPICON_MIN, CPICON_MAX);
 }
 
-void cpicon_construct(entity this)
+void cpicon_construct(entity this, bool isnew)
 {
        this.netname = "Control Point Icon";
 
@@ -133,6 +133,9 @@ void cpicon_construct(entity this)
        this.cp_origin          = this.origin;
        this.cp_bob_origin      = '0 0 0.1';
        this.cp_bob_spd         = 0;
+
+       if(isnew)
+               IL_PUSH(g_drawables, this);
 }
 
 .vector glowmod;
@@ -174,7 +177,7 @@ NET_HANDLE(ENT_CLIENT_CONTROLPOINT_ICON, bool isnew)
                        this.count = (this.health - this.max_health) * frametime;
 
                cpicon_changeteam(this);
-               cpicon_construct(this);
+               cpicon_construct(this, isnew);
        }
 
        if(sf & CPSF_STATUS)
index 15586ea5dcd923d6aab26966dc063d3f534fbc5b..d5437338e3fb47ac0432e6de3b027bd81a366eec 100644 (file)
@@ -1,10 +1,7 @@
-#ifndef CLIENT_CONTROLPOINT_H
-#define CLIENT_CONTROLPOINT_H
+#pragma once
 
 const vector CPICON_MIN = '-32 -32 -9';
 const vector CPICON_MAX = '32 32 25';
 
 const int CPSF_STATUS = 4;
 const int CPSF_SETUP = 8;
-
-#endif
index 2b9470f7750ab2b9fecac82a5abe51590811e6bb..cbba9a9aaa87bc23d183b18b224f9fd508d91080 100644 (file)
@@ -143,11 +143,14 @@ void generator_damage(entity this, float hp)
        setsize(this, GENERATOR_MIN, GENERATOR_MAX);
 }
 
-void generator_construct(entity this)
+void generator_construct(entity this, bool isnew)
 {
        this.netname = "Generator";
        this.classname = "onslaught_generator";
 
+       if(isnew)
+               IL_PUSH(g_onsgenerators, this);
+
        setorigin(this, this.origin);
        setmodel(this, MDL_ONS_GEN);
        setsize(this, GENERATOR_MIN, GENERATOR_MAX);
@@ -199,7 +202,7 @@ NET_HANDLE(ENT_CLIENT_GENERATOR, bool isnew)
                        this.count = 40;
 
                generator_changeteam(this);
-               generator_construct(this);
+               generator_construct(this, isnew);
        }
 
        if(sf & GSF_STATUS)
index 3c0cf28697536f2ad234a24d6ab08c7830e7adec..49524687f42d48d7c13d150f048a1f4dc0767217 100644 (file)
@@ -1,9 +1,7 @@
-#ifndef CLIENT_GENERATOR_H
-#define CLIENT_GENERATOR_H
+#pragma once
+
 const vector GENERATOR_MIN = '-52 -52 -14';
 const vector GENERATOR_MAX = '52 52 75';
 
 const int GSF_STATUS = 4;
 const int GSF_SETUP = 8;
-
-#endif
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/controlpoint.qc b/qcsrc/common/gamemodes/gamemode/onslaught/controlpoint.qc
new file mode 100644 (file)
index 0000000..b21f5fd
--- /dev/null
@@ -0,0 +1 @@
+#include "controlpoint.qh"
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/controlpoint.qh b/qcsrc/common/gamemodes/gamemode/onslaught/controlpoint.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/generator.qc b/qcsrc/common/gamemodes/gamemode/onslaught/generator.qc
new file mode 100644 (file)
index 0000000..f9415f6
--- /dev/null
@@ -0,0 +1 @@
+#include "generator.qh"
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/generator.qh b/qcsrc/common/gamemodes/gamemode/onslaught/generator.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/module.inc b/qcsrc/common/gamemodes/gamemode/onslaught/module.inc
deleted file mode 100644 (file)
index fee33b1..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef ONS_CONSTANTS
-       #define ONS_CONSTANTS
-       REGISTER_NET_LINKED(ENT_CLIENT_GENERATOR)
-       REGISTER_NET_LINKED(ENT_CLIENT_CONTROLPOINT_ICON)
-#endif
-
-#if defined(SVQC)
-       #include "onslaught.qc"
-       #ifndef IMPLEMENTATION
-               #include "sv_controlpoint.qh"
-               #include "sv_generator.qh"
-       #else
-               #include "sv_controlpoint.qc"
-               #include "sv_generator.qc"
-       #endif
-#elif defined(CSQC)
-       #ifndef IMPLEMENTATION
-               #include "cl_controlpoint.qh"
-               #include "cl_generator.qh"
-       #else
-               #include "cl_controlpoint.qc"
-               #include "cl_generator.qc"
-       #endif
-#endif
index a0225f6249feeee8f308dbfaebaa900f96f85deb..36926b754b0bcb8f0c92b4f1c734d8391c3cafc6 100644 (file)
@@ -1,2256 +1 @@
-#ifndef GAMEMODE_ONSLAUGHT_H
-#define GAMEMODE_ONSLAUGHT_H
-
-float autocvar_g_onslaught_point_limit;
-void ons_Initialize();
-
-REGISTER_MUTATOR(ons, false)
-{
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               ons_Initialize();
-
-               ActivateTeamplay();
-               SetLimits(autocvar_g_onslaught_point_limit, autocvar_leadlimit_override, autocvar_timelimit_override, -1);
-               have_team_spawns = -1; // request team spawns
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back ons_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return false;
-}
-
-#ifdef SVQC
-
-.entity ons_toucher; // player who touched the control point
-
-// control point / generator constants
-const float ONS_CP_THINKRATE = 0.2;
-const float GEN_THINKRATE = 1;
-#define CPGEN_SPAWN_OFFSET ('0 0 1' * (PL_MAX_CONST.z - 13))
-const vector CPGEN_WAYPOINT_OFFSET = ('0 0 128');
-const vector CPICON_OFFSET = ('0 0 96');
-
-// list of generators on the map
-entity ons_worldgeneratorlist;
-.entity ons_worldgeneratornext;
-.entity ons_stalegeneratornext;
-
-// list of control points on the map
-entity ons_worldcplist;
-.entity ons_worldcpnext;
-.entity ons_stalecpnext;
-
-// list of links on the map
-entity ons_worldlinklist;
-.entity ons_worldlinknext;
-.entity ons_stalelinknext;
-
-// definitions
-.entity sprite;
-.string target2;
-.int iscaptured;
-.int islinked;
-.int isshielded;
-.float lasthealth;
-.int lastteam;
-.int lastshielded;
-.int lastcaptured;
-
-.bool waslinked;
-
-bool ons_stalemate;
-
-.float teleport_antispam;
-
-// waypoint sprites
-.entity bot_basewaypoint; // generator waypointsprite
-
-.bool isgenneighbor[17];
-.bool iscpneighbor[17];
-float ons_notification_time[17];
-
-.float ons_overtime_damagedelay;
-
-.vector ons_deathloc;
-
-.entity ons_spawn_by;
-
-// declarations for functions used outside gamemode_onslaught.qc
-void ons_Generator_UpdateSprite(entity e);
-void ons_ControlPoint_UpdateSprite(entity e);
-bool ons_ControlPoint_Attackable(entity cp, int teamnumber);
-
-// CaptureShield: Prevent capturing or destroying control point/generator if it is not available yet
-float ons_captureshield_force; // push force of the shield
-
-// bot player logic
-const int HAVOCBOT_ONS_ROLE_NONE               = 0;
-const int HAVOCBOT_ONS_ROLE_DEFENSE    = 2;
-const int HAVOCBOT_ONS_ROLE_ASSISTANT  = 4;
-const int HAVOCBOT_ONS_ROLE_OFFENSE    = 8;
-
-.entity havocbot_ons_target;
-
-.int havocbot_role_flags;
-.float havocbot_attack_time;
-
-void havocbot_role_ons_defense(entity this);
-void havocbot_role_ons_offense(entity this);
-void havocbot_role_ons_assistant(entity this);
-
-void havocbot_ons_reset_role(entity this);
-void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius);
-void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius);
-
-// score rule declarations
-const int ST_ONS_CAPS = 1;
-
-#endif
-#endif
-
-#ifdef IMPLEMENTATION
-
-#include "sv_controlpoint.qh"
-#include "sv_generator.qh"
-
-bool g_onslaught;
-
-float autocvar_g_onslaught_teleport_wait;
-bool autocvar_g_onslaught_spawn_at_controlpoints;
-bool autocvar_g_onslaught_spawn_at_generator;
-float autocvar_g_onslaught_cp_proxydecap;
-float autocvar_g_onslaught_cp_proxydecap_distance = 512;
-float autocvar_g_onslaught_cp_proxydecap_dps = 100;
-float autocvar_g_onslaught_spawn_at_controlpoints_chance = 0.5;
-float autocvar_g_onslaught_spawn_at_controlpoints_random;
-float autocvar_g_onslaught_spawn_at_generator_chance;
-float autocvar_g_onslaught_spawn_at_generator_random;
-float autocvar_g_onslaught_cp_buildhealth;
-float autocvar_g_onslaught_cp_buildtime;
-float autocvar_g_onslaught_cp_health;
-float autocvar_g_onslaught_cp_regen;
-float autocvar_g_onslaught_gen_health;
-float autocvar_g_onslaught_shield_force = 100;
-float autocvar_g_onslaught_allow_vehicle_touch;
-float autocvar_g_onslaught_round_timelimit;
-float autocvar_g_onslaught_warmup;
-float autocvar_g_onslaught_teleport_radius;
-float autocvar_g_onslaught_spawn_choose;
-float autocvar_g_onslaught_click_radius;
-
-void FixSize(entity e);
-
-// =======================
-// CaptureShield Functions
-// =======================
-
-bool ons_CaptureShield_Customize(entity this, entity client)
-{
-       entity e = WaypointSprite_getviewentity(client);
-
-       if(!this.enemy.isshielded && (ons_ControlPoint_Attackable(this.enemy, e.team) > 0 || this.enemy.classname != "onslaught_controlpoint")) { return false; }
-       if(SAME_TEAM(this, e)) { return false; }
-
-       return true;
-}
-
-void ons_CaptureShield_Touch(entity this, entity toucher)
-{
-       if(!this.enemy.isshielded && (ons_ControlPoint_Attackable(this.enemy, toucher.team) > 0 || this.enemy.classname != "onslaught_controlpoint")) { return; }
-       if(!IS_PLAYER(toucher)) { return; }
-       if(SAME_TEAM(toucher, this)) { return; }
-
-       vector mymid = (this.absmin + this.absmax) * 0.5;
-       vector theirmid = (toucher.absmin + toucher.absmax) * 0.5;
-
-       Damage(toucher, this, this, 0, DEATH_HURTTRIGGER.m_id, mymid, normalize(theirmid - mymid) * ons_captureshield_force);
-
-       if(IS_REAL_CLIENT(toucher))
-       {
-               play2(toucher, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
-
-               if(this.enemy.classname == "onslaught_generator")
-                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_GENERATOR_SHIELDED);
-               else
-                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_CONTROLPOINT_SHIELDED);
-       }
-}
-
-void ons_CaptureShield_Reset(entity this)
-{
-       this.colormap = this.enemy.colormap;
-       this.team = this.enemy.team;
-}
-
-void ons_CaptureShield_Spawn(entity generator, bool is_generator)
-{
-       entity shield = new(ons_captureshield);
-
-       shield.enemy = generator;
-       shield.team = generator.team;
-       shield.colormap = generator.colormap;
-       shield.reset = ons_CaptureShield_Reset;
-       settouch(shield, ons_CaptureShield_Touch);
-       setcefc(shield, ons_CaptureShield_Customize);
-       shield.effects = EF_ADDITIVE;
-       set_movetype(shield, MOVETYPE_NOCLIP);
-       shield.solid = SOLID_TRIGGER;
-       shield.avelocity = '7 0 11';
-       shield.scale = 1;
-       shield.model = ((is_generator) ? "models/onslaught/generator_shield.md3" : "models/onslaught/controlpoint_shield.md3");
-
-       precache_model(shield.model);
-       setorigin(shield, generator.origin);
-       _setmodel(shield, shield.model);
-       setsize(shield, shield.scale * shield.mins, shield.scale * shield.maxs);
-}
-
-
-// ==========
-// Junk Pile
-// ==========
-
-void setmodel_fixsize(entity e, Model m)
-{
-       setmodel(e, m);
-       FixSize(e);
-}
-
-void onslaught_updatelinks()
-{
-       entity l;
-       // first check if the game has ended
-       LOG_DEBUG("--- updatelinks ---");
-       // mark generators as being shielded and networked
-       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
-       {
-               if (l.iscaptured)
-                       LOG_DEBUG(etos(l), " (generator) belongs to team ", ftos(l.team));
-               else
-                       LOG_DEBUG(etos(l), " (generator) is destroyed");
-               l.islinked = l.iscaptured;
-               l.isshielded = l.iscaptured;
-               l.sprite.SendFlags |= 16;
-       }
-       // mark points as shielded and not networked
-       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
-       {
-               l.islinked = false;
-               l.isshielded = true;
-               int i;
-               for(i = 0; i < 17; ++i) { l.isgenneighbor[i] = false; l.iscpneighbor[i] = false; }
-               LOG_DEBUG(etos(l), " (point) belongs to team ", ftos(l.team));
-               l.sprite.SendFlags |= 16;
-       }
-       // flow power outward from the generators through the network
-       bool stop = false;
-       while (!stop)
-       {
-               stop = true;
-               for(l = ons_worldlinklist; l; l = l.ons_worldlinknext)
-               {
-                       // if both points are captured by the same team, and only one of
-                       // them is powered, mark the other one as powered as well
-                       if (l.enemy.iscaptured && l.goalentity.iscaptured)
-                               if (l.enemy.islinked != l.goalentity.islinked)
-                                       if(SAME_TEAM(l.enemy, l.goalentity))
-                                       {
-                                               if (!l.goalentity.islinked)
-                                               {
-                                                       stop = false;
-                                                       l.goalentity.islinked = true;
-                                                       LOG_DEBUG(etos(l), " (link) is marking ", etos(l.goalentity), " (point) because its team matches ", etos(l.enemy), " (point)");
-                                               }
-                                               else if (!l.enemy.islinked)
-                                               {
-                                                       stop = false;
-                                                       l.enemy.islinked = true;
-                                                       LOG_DEBUG(etos(l), " (link) is marking ", etos(l.enemy), " (point) because its team matches ", etos(l.goalentity), " (point)");
-                                               }
-                                       }
-               }
-       }
-       // now that we know which points are powered we can mark their neighbors
-       // as unshielded if team differs
-       for(l = ons_worldlinklist; l; l = l.ons_worldlinknext)
-       {
-               if (l.goalentity.islinked)
-               {
-                       if(DIFF_TEAM(l.goalentity, l.enemy))
-                       {
-                               LOG_DEBUG(etos(l), " (link) is unshielding ", etos(l.enemy), " (point) because its team does not match ", etos(l.goalentity), " (point)");
-                               l.enemy.isshielded = false;
-                       }
-                       if(l.goalentity.classname == "onslaught_generator")
-                               l.enemy.isgenneighbor[l.goalentity.team] = true;
-                       else
-                               l.enemy.iscpneighbor[l.goalentity.team] = true;
-               }
-               if (l.enemy.islinked)
-               {
-                       if(DIFF_TEAM(l.goalentity, l.enemy))
-                       {
-                               LOG_DEBUG(etos(l), " (link) is unshielding ", etos(l.goalentity), " (point) because its team does not match ", etos(l.enemy), " (point)");
-                               l.goalentity.isshielded = false;
-                       }
-                       if(l.enemy.classname == "onslaught_generator")
-                               l.goalentity.isgenneighbor[l.enemy.team] = true;
-                       else
-                               l.goalentity.iscpneighbor[l.enemy.team] = true;
-               }
-       }
-       // now update the generators
-       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
-       {
-               if (l.isshielded)
-               {
-                       LOG_DEBUG(etos(l), " (generator) is shielded");
-                       l.takedamage = DAMAGE_NO;
-                       l.bot_attack = false;
-               }
-               else
-               {
-                       LOG_DEBUG(etos(l), " (generator) is not shielded");
-                       l.takedamage = DAMAGE_AIM;
-                       l.bot_attack = true;
-               }
-
-               ons_Generator_UpdateSprite(l);
-       }
-       // now update the takedamage and alpha variables on control point icons
-       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
-       {
-               if (l.isshielded)
-               {
-                       LOG_DEBUG(etos(l), " (point) is shielded");
-                       if (l.goalentity)
-                       {
-                               l.goalentity.takedamage = DAMAGE_NO;
-                               l.goalentity.bot_attack = false;
-                       }
-               }
-               else
-               {
-                       LOG_DEBUG(etos(l), " (point) is not shielded");
-                       if (l.goalentity)
-                       {
-                               l.goalentity.takedamage = DAMAGE_AIM;
-                               l.goalentity.bot_attack = true;
-                       }
-               }
-               ons_ControlPoint_UpdateSprite(l);
-       }
-       FOREACH_ENTITY_CLASS("ons_captureshield", true,
-       {
-               it.team = it.enemy.team;
-               it.colormap = it.enemy.colormap;
-       });
-}
-
-
-// ===================
-// Main Link Functions
-// ===================
-
-bool ons_Link_Send(entity this, entity to, int sendflags)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_RADARLINK);
-       WriteByte(MSG_ENTITY, sendflags);
-       if(sendflags & 1)
-       {
-               WriteCoord(MSG_ENTITY, this.goalentity.origin_x);
-               WriteCoord(MSG_ENTITY, this.goalentity.origin_y);
-               WriteCoord(MSG_ENTITY, this.goalentity.origin_z);
-       }
-       if(sendflags & 2)
-       {
-               WriteCoord(MSG_ENTITY, this.enemy.origin_x);
-               WriteCoord(MSG_ENTITY, this.enemy.origin_y);
-               WriteCoord(MSG_ENTITY, this.enemy.origin_z);
-       }
-       if(sendflags & 4)
-       {
-               WriteByte(MSG_ENTITY, this.clientcolors); // which is goalentity's color + enemy's color * 16
-       }
-       return true;
-}
-
-void ons_Link_CheckUpdate(entity this)
-{
-       // TODO check if the two sides have moved (currently they won't move anyway)
-       float cc = 0, cc1 = 0, cc2 = 0;
-
-       if(this.goalentity.islinked || this.goalentity.iscaptured) { cc1 = (this.goalentity.team - 1) * 0x01; }
-       if(this.enemy.islinked || this.enemy.iscaptured) { cc2 = (this.enemy.team - 1) * 0x10; }
-
-       cc = cc1 + cc2;
-
-       if(cc != this.clientcolors)
-       {
-               this.clientcolors = cc;
-               this.SendFlags |= 4;
-       }
-
-       this.nextthink = time;
-}
-
-void ons_DelayedLinkSetup(entity this)
-{
-       this.goalentity = find(NULL, targetname, this.target);
-       this.enemy = find(NULL, targetname, this.target2);
-       if(!this.goalentity) { objerror(this, "can not find target\n"); }
-       if(!this.enemy) { objerror(this, "can not find target2\n"); }
-
-       LOG_DEBUG(etos(this.goalentity), " linked with ", etos(this.enemy));
-       this.SendFlags |= 3;
-       setthink(this, ons_Link_CheckUpdate);
-       this.nextthink = time;
-}
-
-
-// =============================
-// Main Control Point Functions
-// =============================
-
-int ons_ControlPoint_CanBeLinked(entity cp, int teamnumber)
-{
-       if(cp.isgenneighbor[teamnumber]) { return 2; }
-       if(cp.iscpneighbor[teamnumber]) { return 1; }
-
-       return 0;
-}
-
-int ons_ControlPoint_Attackable(entity cp, int teamnumber)
-       // -2: SAME TEAM, attackable by enemy!
-       // -1: SAME TEAM!
-       // 0: off limits
-       // 1: attack it
-       // 2: touch it
-       // 3: attack it (HIGH PRIO)
-       // 4: touch it (HIGH PRIO)
-{
-       int a;
-
-       if(cp.isshielded)
-       {
-               return 0;
-       }
-       else if(cp.goalentity)
-       {
-               // if there's already an icon built, nothing happens
-               if(cp.team == teamnumber)
-               {
-                       a = ons_ControlPoint_CanBeLinked(cp, teamnumber);
-                       if(a) // attackable by enemy?
-                               return -2; // EMERGENCY!
-                       return -1;
-               }
-               // we know it can be linked, so no need to check
-               // but...
-               a = ons_ControlPoint_CanBeLinked(cp, teamnumber);
-               if(a == 2) // near our generator?
-                       return 3; // EMERGENCY!
-               return 1;
-       }
-       else
-       {
-               // free point
-               if(ons_ControlPoint_CanBeLinked(cp, teamnumber))
-               {
-                       a = ons_ControlPoint_CanBeLinked(cp, teamnumber); // why was this here NUM_TEAM_1 + NUM_TEAM_2 - t
-                       if(a == 2)
-                               return 4; // GET THIS ONE NOW!
-                       else
-                               return 2; // TOUCH ME
-               }
-       }
-       return 0;
-}
-
-void ons_ControlPoint_Icon_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{
-       if(damage <= 0) { return; }
-
-       if (this.owner.isshielded)
-       {
-               // this is protected by a shield, so ignore the damage
-               if (time > this.pain_finished)
-                       if (IS_PLAYER(attacker))
-                       {
-                               play2(attacker, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
-                               this.pain_finished = time + 1;
-                               attacker.typehitsound += 1; // play both sounds (shield is way too quiet)
-                       }
-
-               return;
-       }
-
-       if(IS_PLAYER(attacker))
-       if(time - ons_notification_time[this.team] > 10)
-       {
-               play2team(this.team, SND(ONS_CONTROLPOINT_UNDERATTACK));
-               ons_notification_time[this.team] = time;
-       }
-
-       this.health = this.health - damage;
-       if(this.owner.iscaptured)
-               WaypointSprite_UpdateHealth(this.owner.sprite, this.health);
-       else
-               WaypointSprite_UpdateBuildFinished(this.owner.sprite, time + (this.max_health - this.health) / (this.count / ONS_CP_THINKRATE));
-       this.pain_finished = time + 1;
-       // particles on every hit
-       pointparticles(EFFECT_SPARKS, hitloc, force*-1, 1);
-       //sound on every hit
-       if (random() < 0.5)
-               sound(this, CH_TRIGGER, SND_ONS_HIT1, VOL_BASE+0.3, ATTEN_NORM);
-       else
-               sound(this, CH_TRIGGER, SND_ONS_HIT2, VOL_BASE+0.3, ATTEN_NORM);
-
-       if (this.health < 0)
-       {
-               sound(this, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
-               pointparticles(EFFECT_ROCKET_EXPLODE, this.origin, '0 0 0', 1);
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_ONSLAUGHT_CPDESTROYED), this.owner.message, attacker.netname);
-
-               PlayerScore_Add(attacker, SP_ONS_TAKES, 1);
-               PlayerScore_Add(attacker, SP_SCORE, 10);
-
-               this.owner.goalentity = NULL;
-               this.owner.islinked = false;
-               this.owner.iscaptured = false;
-               this.owner.team = 0;
-               this.owner.colormap = 1024;
-
-               WaypointSprite_UpdateMaxHealth(this.owner.sprite, 0);
-
-               onslaught_updatelinks();
-
-               // Use targets now (somebody make sure this is in the right place..)
-               SUB_UseTargets(this.owner, this, NULL);
-
-               this.owner.waslinked = this.owner.islinked;
-               if(this.owner.model != "models/onslaught/controlpoint_pad.md3")
-                       setmodel_fixsize(this.owner, MDL_ONS_CP_PAD1);
-               //setsize(this, '-32 -32 0', '32 32 8');
-
-               delete(this);
-       }
-
-       this.SendFlags |= CPSF_STATUS;
-}
-
-void ons_ControlPoint_Icon_Think(entity this)
-{
-       this.nextthink = time + ONS_CP_THINKRATE;
-
-       if(autocvar_g_onslaught_cp_proxydecap)
-       {
-               int _enemy_count = 0;
-               int _friendly_count = 0;
-
-               FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
-                       if(vdist(it.origin - this.origin, <, autocvar_g_onslaught_cp_proxydecap_distance))
-                       {
-                               if(SAME_TEAM(it, this))
-                                       ++_friendly_count;
-                               else
-                                       ++_enemy_count;
-                       }
-               });
-
-               _friendly_count = _friendly_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
-               _enemy_count = _enemy_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
-
-               this.health = bound(0, this.health + (_friendly_count - _enemy_count), this.max_health);
-               this.SendFlags |= CPSF_STATUS;
-               if(this.health <= 0)
-               {
-                       ons_ControlPoint_Icon_Damage(this, this, this, 1, 0, this.origin, '0 0 0');
-                       return;
-               }
-       }
-
-       if (time > this.pain_finished + 5)
-       {
-               if(this.health < this.max_health)
-               {
-                       this.health = this.health + this.count;
-                       if (this.health >= this.max_health)
-                               this.health = this.max_health;
-                       WaypointSprite_UpdateHealth(this.owner.sprite, this.health);
-               }
-       }
-
-       if(this.owner.islinked != this.owner.waslinked)
-       {
-               // unteam the spawnpoint if needed
-               int t = this.owner.team;
-               if(!this.owner.islinked)
-                       this.owner.team = 0;
-
-               SUB_UseTargets(this.owner, this, NULL);
-
-               this.owner.team = t;
-
-               this.owner.waslinked = this.owner.islinked;
-       }
-
-       // damaged fx
-       if(random() < 0.6 - this.health / this.max_health)
-       {
-               Send_Effect(EFFECT_ELECTRIC_SPARKS, this.origin + randompos('-10 -10 -20', '10 10 20'), '0 0 0', 1);
-
-               if(random() > 0.8)
-                       sound(this, CH_PAIN, SND_ONS_SPARK1, VOL_BASE, ATTEN_NORM);
-               else if (random() > 0.5)
-                       sound(this, CH_PAIN, SND_ONS_SPARK2, VOL_BASE, ATTEN_NORM);
-       }
-}
-
-void ons_ControlPoint_Icon_BuildThink(entity this)
-{
-       int a;
-
-       this.nextthink = time + ONS_CP_THINKRATE;
-
-       // only do this if there is power
-       a = ons_ControlPoint_CanBeLinked(this.owner, this.owner.team);
-       if(!a)
-               return;
-
-       this.health = this.health + this.count;
-
-       this.SendFlags |= CPSF_STATUS;
-
-       if (this.health >= this.max_health)
-       {
-               this.health = this.max_health;
-               this.count = autocvar_g_onslaught_cp_regen * ONS_CP_THINKRATE; // slow repair rate from now on
-               setthink(this, ons_ControlPoint_Icon_Think);
-               sound(this, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILT, VOL_BASE, ATTEN_NORM);
-               this.owner.iscaptured = true;
-               this.solid = SOLID_BBOX;
-
-               Send_Effect(EFFECT_CAP(this.owner.team), this.owner.origin, '0 0 0', 1);
-
-               WaypointSprite_UpdateMaxHealth(this.owner.sprite, this.max_health);
-               WaypointSprite_UpdateHealth(this.owner.sprite, this.health);
-
-               if(IS_PLAYER(this.owner.ons_toucher))
-               {
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ONSLAUGHT_CAPTURE, this.owner.ons_toucher.netname, this.owner.message);
-                       Send_Notification(NOTIF_ALL_EXCEPT, this.owner.ons_toucher, MSG_CENTER, APP_TEAM_NUM(this.owner.ons_toucher.team, CENTER_ONS_CAPTURE), this.owner.message);
-                       Send_Notification(NOTIF_ONE, this.owner.ons_toucher, MSG_CENTER, CENTER_ONS_CAPTURE, this.owner.message);
-                       PlayerScore_Add(this.owner.ons_toucher, SP_ONS_CAPS, 1);
-                       PlayerTeamScore_AddScore(this.owner.ons_toucher, 10);
-               }
-
-               this.owner.ons_toucher = NULL;
-
-               onslaught_updatelinks();
-
-               // Use targets now (somebody make sure this is in the right place..)
-               SUB_UseTargets(this.owner, this, NULL);
-
-               this.SendFlags |= CPSF_SETUP;
-       }
-       if(this.owner.model != MDL_ONS_CP_PAD2.model_str())
-               setmodel_fixsize(this.owner, MDL_ONS_CP_PAD2);
-
-       if(random() < 0.9 - this.health / this.max_health)
-               Send_Effect(EFFECT_RAGE, this.origin + 10 * randomvec(), '0 0 -1', 1);
-}
-
-void onslaught_controlpoint_icon_link(entity e, void(entity this) spawnproc);
-
-void ons_ControlPoint_Icon_Spawn(entity cp, entity player)
-{
-       entity e = new(onslaught_controlpoint_icon);
-
-       setsize(e, CPICON_MIN, CPICON_MAX);
-       setorigin(e, cp.origin + CPICON_OFFSET);
-
-       e.owner = cp;
-       e.max_health = autocvar_g_onslaught_cp_health;
-       e.health = autocvar_g_onslaught_cp_buildhealth;
-       e.solid = SOLID_NOT;
-       e.takedamage = DAMAGE_AIM;
-       e.bot_attack = true;
-       e.event_damage = ons_ControlPoint_Icon_Damage;
-       e.team = player.team;
-       e.colormap = 1024 + (e.team - 1) * 17;
-       e.count = (e.max_health - e.health) * ONS_CP_THINKRATE / autocvar_g_onslaught_cp_buildtime; // how long it takes to build
-
-       sound(e, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILD, VOL_BASE, ATTEN_NORM);
-
-       cp.goalentity = e;
-       cp.team = e.team;
-       cp.colormap = e.colormap;
-
-       Send_Effect(EFFECT_FLAG_TOUCH(player.team), e.origin, '0 0 0', 1);
-
-       WaypointSprite_UpdateBuildFinished(cp.sprite, time + (e.max_health - e.health) / (e.count / ONS_CP_THINKRATE));
-       WaypointSprite_UpdateRule(cp.sprite,cp.team,SPRITERULE_TEAMPLAY);
-       cp.sprite.SendFlags |= 16;
-
-       onslaught_controlpoint_icon_link(e, ons_ControlPoint_Icon_BuildThink);
-}
-
-entity ons_ControlPoint_Waypoint(entity e)
-{
-       if(e.team)
-       {
-               int a = ons_ControlPoint_Attackable(e, e.team);
-
-               if(a == -2) { return WP_OnsCPDefend; } // defend now
-               if(a == -1 || a == 1 || a == 2) { return WP_OnsCP; } // touch
-               if(a == 3 || a == 4) { return WP_OnsCPAttack; } // attack
-       }
-       else
-               return WP_OnsCP;
-
-       return WP_Null;
-}
-
-void ons_ControlPoint_UpdateSprite(entity e)
-{
-       entity s1 = ons_ControlPoint_Waypoint(e);
-       WaypointSprite_UpdateSprites(e.sprite, s1, s1, s1);
-
-       bool sh;
-       sh = !(ons_ControlPoint_CanBeLinked(e, NUM_TEAM_1) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_2) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_3) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_4));
-
-       if(e.lastteam != e.team + 2 || e.lastshielded != sh || e.iscaptured != e.lastcaptured)
-       {
-               if(e.iscaptured) // don't mess up build bars!
-               {
-                       if(sh)
-                       {
-                               WaypointSprite_UpdateMaxHealth(e.sprite, 0);
-                       }
-                       else
-                       {
-                               WaypointSprite_UpdateMaxHealth(e.sprite, e.goalentity.max_health);
-                               WaypointSprite_UpdateHealth(e.sprite, e.goalentity.health);
-                       }
-               }
-               if(e.lastshielded)
-               {
-                       if(e.team)
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, 0.5 * colormapPaletteColor(e.team - 1, false));
-                       else
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.5 0.5 0.5');
-               }
-               else
-               {
-                       if(e.team)
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, colormapPaletteColor(e.team - 1, false));
-                       else
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.75 0.75 0.75');
-               }
-               WaypointSprite_Ping(e.sprite);
-
-               e.lastteam = e.team + 2;
-               e.lastshielded = sh;
-               e.lastcaptured = e.iscaptured;
-       }
-}
-
-void ons_ControlPoint_Touch(entity this, entity toucher)
-{
-       int attackable;
-
-       if(IS_VEHICLE(toucher) && toucher.owner)
-       if(autocvar_g_onslaught_allow_vehicle_touch)
-               toucher = toucher.owner;
-       else
-               return;
-
-       if(!IS_PLAYER(toucher)) { return; }
-       if(STAT(FROZEN, toucher)) { return; }
-       if(IS_DEAD(toucher)) { return; }
-
-       if ( SAME_TEAM(this,toucher) )
-       if ( this.iscaptured )
-       {
-               if(time <= toucher.teleport_antispam)
-                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT_ANTISPAM, rint(toucher.teleport_antispam - time));
-               else
-                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT);
-       }
-
-       attackable = ons_ControlPoint_Attackable(this, toucher.team);
-       if(attackable != 2 && attackable != 4)
-               return;
-       // we've verified that this player has a legitimate claim to this point,
-       // so start building the captured point icon (which only captures this
-       // point if it successfully builds without being destroyed first)
-       ons_ControlPoint_Icon_Spawn(this, toucher);
-
-       this.ons_toucher = toucher;
-
-       onslaught_updatelinks();
-}
-
-void ons_ControlPoint_Think(entity this)
-{
-       this.nextthink = time + ONS_CP_THINKRATE;
-       CSQCMODEL_AUTOUPDATE(this);
-}
-
-void ons_ControlPoint_Reset(entity this)
-{
-       if(this.goalentity)
-               delete(this.goalentity);
-
-       this.goalentity = NULL;
-       this.team = 0;
-       this.colormap = 1024;
-       this.iscaptured = false;
-       this.islinked = false;
-       this.isshielded = true;
-       setthink(this, ons_ControlPoint_Think);
-       this.ons_toucher = NULL;
-       this.nextthink = time + ONS_CP_THINKRATE;
-       setmodel_fixsize(this, MDL_ONS_CP_PAD1);
-
-       WaypointSprite_UpdateMaxHealth(this.sprite, 0);
-       WaypointSprite_UpdateRule(this.sprite,this.team,SPRITERULE_TEAMPLAY);
-
-       onslaught_updatelinks();
-
-       SUB_UseTargets(this, this, NULL); // to reset the structures, playerspawns etc.
-
-       CSQCMODEL_AUTOUPDATE(this);
-}
-
-void ons_DelayedControlPoint_Setup(entity this)
-{
-       onslaught_updatelinks();
-
-       // captureshield setup
-       ons_CaptureShield_Spawn(this, false);
-
-       CSQCMODEL_AUTOINIT(this);
-}
-
-void ons_ControlPoint_Setup(entity cp)
-{
-       // main setup
-       cp.ons_worldcpnext = ons_worldcplist; // link control point into ons_worldcplist
-       ons_worldcplist = cp;
-
-       cp.netname = "Control point";
-       cp.team = 0;
-       cp.solid = SOLID_BBOX;
-       set_movetype(cp, MOVETYPE_NONE);
-       settouch(cp, ons_ControlPoint_Touch);
-       setthink(cp, ons_ControlPoint_Think);
-       cp.nextthink = time + ONS_CP_THINKRATE;
-       cp.reset = ons_ControlPoint_Reset;
-       cp.colormap = 1024;
-       cp.iscaptured = false;
-       cp.islinked = false;
-       cp.isshielded = true;
-
-       if(cp.message == "") { cp.message = "a"; }
-
-       // appearence
-       setmodel_fixsize(cp, MDL_ONS_CP_PAD1);
-
-       // control point placement
-       if((cp.spawnflags & 1) || cp.noalign) // don't drop to floor, just stay at fixed location
-       {
-               cp.noalign = true;
-               set_movetype(cp, MOVETYPE_NONE);
-       }
-       else // drop to floor, automatically find a platform and set that as spawn origin
-       {
-               setorigin(cp, cp.origin + '0 0 20');
-               cp.noalign = false;
-               droptofloor(cp);
-               set_movetype(cp, MOVETYPE_TOSS);
-       }
-
-       // waypointsprites
-       WaypointSprite_SpawnFixed(WP_Null, cp.origin + CPGEN_WAYPOINT_OFFSET, cp, sprite, RADARICON_NONE);
-       WaypointSprite_UpdateRule(cp.sprite, cp.team, SPRITERULE_TEAMPLAY);
-
-       InitializeEntity(cp, ons_DelayedControlPoint_Setup, INITPRIO_SETLOCATION);
-}
-
-
-// =========================
-// Main Generator Functions
-// =========================
-
-entity ons_Generator_Waypoint(entity e)
-{
-       if (e.isshielded)
-               return WP_OnsGenShielded;
-       return WP_OnsGen;
-}
-
-void ons_Generator_UpdateSprite(entity e)
-{
-       entity s1 = ons_Generator_Waypoint(e);
-       WaypointSprite_UpdateSprites(e.sprite, s1, s1, s1);
-
-       if(e.lastteam != e.team + 2 || e.lastshielded != e.isshielded)
-       {
-               e.lastteam = e.team + 2;
-               e.lastshielded = e.isshielded;
-               if(e.lastshielded)
-               {
-                       if(e.team)
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, 0.5 * colormapPaletteColor(e.team - 1, false));
-                       else
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.5 0.5 0.5');
-               }
-               else
-               {
-                       if(e.team)
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, colormapPaletteColor(e.team - 1, false));
-                       else
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.75 0.75 0.75');
-               }
-               WaypointSprite_Ping(e.sprite);
-       }
-}
-
-void ons_GeneratorDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{
-       if(damage <= 0) { return; }
-       if(warmup_stage || gameover) { return; }
-       if(!round_handler_IsRoundStarted()) { return; }
-
-       if (attacker != this)
-       {
-               if (this.isshielded)
-               {
-                       // this is protected by a shield, so ignore the damage
-                       if (time > this.pain_finished)
-                               if (IS_PLAYER(attacker))
-                               {
-                                       play2(attacker, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
-                                       attacker.typehitsound += 1;
-                                       this.pain_finished = time + 1;
-                               }
-                       return;
-               }
-               if (time > this.pain_finished)
-               {
-                       this.pain_finished = time + 10;
-                       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && SAME_TEAM(it, this), Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_GENERATOR_UNDERATTACK));
-                       play2team(this.team, SND(ONS_GENERATOR_UNDERATTACK));
-               }
-       }
-       this.health = this.health - damage;
-       WaypointSprite_UpdateHealth(this.sprite, this.health);
-       // choose an animation frame based on health
-       this.frame = 10 * bound(0, (1 - this.health / this.max_health), 1);
-       // see if the generator is still functional, or dying
-       if (this.health > 0)
-       {
-               this.lasthealth = this.health;
-       }
-       else
-       {
-               if (attacker == this)
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_ONSLAUGHT_GENDESTROYED_OVERTIME));
-               else
-               {
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_ONSLAUGHT_GENDESTROYED));
-                       PlayerScore_Add(attacker, SP_SCORE, 100);
-               }
-               this.iscaptured = false;
-               this.islinked = false;
-               this.isshielded = false;
-               this.takedamage = DAMAGE_NO; // can't be hurt anymore
-               this.event_damage = func_null; // won't do anything if hurt
-               this.count = 0; // reset counter
-               setthink(this, func_null);
-               this.nextthink = 0;
-               //this.think(); // do the first explosion now
-
-               WaypointSprite_UpdateMaxHealth(this.sprite, 0);
-               WaypointSprite_Ping(this.sprite);
-               //WaypointSprite_Kill(this.sprite); // can't do this yet, code too poor
-
-               onslaught_updatelinks();
-       }
-
-       // Throw some flaming gibs on damage, more damage = more chance for gib
-       if(random() < damage/220)
-       {
-               sound(this, CH_TRIGGER, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-       }
-       else
-       {
-               // particles on every hit
-               Send_Effect(EFFECT_SPARKS, hitloc, force * -1, 1);
-
-               //sound on every hit
-               if (random() < 0.5)
-                       sound(this, CH_TRIGGER, SND_ONS_HIT1, VOL_BASE, ATTEN_NORM);
-               else
-                       sound(this, CH_TRIGGER, SND_ONS_HIT2, VOL_BASE, ATTEN_NORM);
-       }
-
-       this.SendFlags |= GSF_STATUS;
-}
-
-void ons_GeneratorThink(entity this)
-{
-       this.nextthink = time + GEN_THINKRATE;
-       if (!gameover)
-       {
-               if(!this.isshielded && this.wait < time)
-               {
-                       this.wait = time + 5;
-                       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
-                               if(SAME_TEAM(it, this))
-                               {
-                                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_ONS_NOTSHIELDED_TEAM);
-                                       soundto(MSG_ONE, it, CHAN_AUTO, SND(KH_ALARM), VOL_BASE, ATTEN_NONE);    // FIXME: unique sound?
-                               }
-                               else
-                                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_TEAM_NUM(this.team, CENTER_ONS_NOTSHIELDED));
-                       });
-               }
-       }
-}
-
-void ons_GeneratorReset(entity this)
-{
-       this.team = this.team_saved;
-       this.lasthealth = this.max_health = this.health = autocvar_g_onslaught_gen_health;
-       this.takedamage = DAMAGE_AIM;
-       this.bot_attack = true;
-       this.iscaptured = true;
-       this.islinked = true;
-       this.isshielded = true;
-       this.event_damage = ons_GeneratorDamage;
-       setthink(this, ons_GeneratorThink);
-       this.nextthink = time + GEN_THINKRATE;
-
-       Net_LinkEntity(this, false, 0, generator_send);
-
-       this.SendFlags = GSF_SETUP; // just incase
-       this.SendFlags |= GSF_STATUS;
-
-       WaypointSprite_UpdateMaxHealth(this.sprite, this.max_health);
-       WaypointSprite_UpdateHealth(this.sprite, this.health);
-       WaypointSprite_UpdateRule(this.sprite,this.team,SPRITERULE_TEAMPLAY);
-
-       onslaught_updatelinks();
-}
-
-void ons_DelayedGeneratorSetup(entity this)
-{
-       // bot waypoints
-       waypoint_spawnforitem_force(this, this.origin);
-       this.nearestwaypointtimeout = 0; // activate waypointing again
-       this.bot_basewaypoint = this.nearestwaypoint;
-
-       // captureshield setup
-       ons_CaptureShield_Spawn(this, true);
-
-       onslaught_updatelinks();
-
-       Net_LinkEntity(this, false, 0, generator_send);
-}
-
-
-void onslaught_generator_touch(entity this, entity toucher)
-{
-       if ( IS_PLAYER(toucher) )
-       if ( SAME_TEAM(this,toucher) )
-       if ( this.iscaptured )
-       {
-               Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT);
-       }
-}
-
-void ons_GeneratorSetup(entity gen) // called when spawning a generator entity on the map as a spawnfunc
-{
-       // declarations
-       int teamnumber = gen.team;
-
-       // main setup
-       gen.ons_worldgeneratornext = ons_worldgeneratorlist; // link generator into ons_worldgeneratorlist
-       ons_worldgeneratorlist = gen;
-
-       gen.netname = sprintf("%s generator", Team_ColoredFullName(teamnumber));
-       gen.classname = "onslaught_generator";
-       gen.solid = SOLID_BBOX;
-       gen.team_saved = teamnumber;
-       set_movetype(gen, MOVETYPE_NONE);
-       gen.lasthealth = gen.max_health = gen.health = autocvar_g_onslaught_gen_health;
-       gen.takedamage = DAMAGE_AIM;
-       gen.bot_attack = true;
-       gen.event_damage = ons_GeneratorDamage;
-       gen.reset = ons_GeneratorReset;
-       setthink(gen, ons_GeneratorThink);
-       gen.nextthink = time + GEN_THINKRATE;
-       gen.iscaptured = true;
-       gen.islinked = true;
-       gen.isshielded = true;
-       settouch(gen, onslaught_generator_touch);
-
-       // appearence
-       // model handled by CSQC
-       setsize(gen, GENERATOR_MIN, GENERATOR_MAX);
-       setorigin(gen, (gen.origin + CPGEN_SPAWN_OFFSET));
-       gen.colormap = 1024 + (teamnumber - 1) * 17;
-
-       // generator placement
-       droptofloor(gen);
-
-       // waypointsprites
-       WaypointSprite_SpawnFixed(WP_Null, gen.origin + CPGEN_WAYPOINT_OFFSET, gen, sprite, RADARICON_NONE);
-       WaypointSprite_UpdateRule(gen.sprite, gen.team, SPRITERULE_TEAMPLAY);
-       WaypointSprite_UpdateMaxHealth(gen.sprite, gen.max_health);
-       WaypointSprite_UpdateHealth(gen.sprite, gen.health);
-
-       InitializeEntity(gen, ons_DelayedGeneratorSetup, INITPRIO_SETLOCATION);
-}
-
-
-// ===============
-//  Round Handler
-// ===============
-
-int total_generators;
-void Onslaught_count_generators()
-{
-       entity e;
-       total_generators = redowned = blueowned = yellowowned = pinkowned = 0;
-       for(e = ons_worldgeneratorlist; e; e = e.ons_worldgeneratornext)
-       {
-               ++total_generators;
-               redowned += (e.team == NUM_TEAM_1 && e.health > 0);
-               blueowned += (e.team == NUM_TEAM_2 && e.health > 0);
-               yellowowned += (e.team == NUM_TEAM_3 && e.health > 0);
-               pinkowned += (e.team == NUM_TEAM_4 && e.health > 0);
-       }
-}
-
-int Onslaught_GetWinnerTeam()
-{
-       int winner_team = 0;
-       if(redowned > 0)
-               winner_team = NUM_TEAM_1;
-       if(blueowned > 0)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_2;
-       }
-       if(yellowowned > 0)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_3;
-       }
-       if(pinkowned > 0)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_4;
-       }
-       if(winner_team)
-               return winner_team;
-       return -1; // no generators left?
-}
-
-void nades_Clear(entity e);
-
-#define ONS_OWNED_GENERATORS() ((redowned > 0) + (blueowned > 0) + (yellowowned > 0) + (pinkowned > 0))
-#define ONS_OWNED_GENERATORS_OK() (ONS_OWNED_GENERATORS() > 1)
-bool Onslaught_CheckWinner()
-{
-       if ((autocvar_timelimit && time > game_starttime + autocvar_timelimit * 60) || (round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0))
-       {
-               ons_stalemate = true;
-
-               if (!wpforenemy_announced)
-               {
-                       Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_CONTROLPOINT);
-                       sound(NULL, CH_INFO, SND_ONS_GENERATOR_DECAY, VOL_BASE, ATTEN_NONE);
-
-                       wpforenemy_announced = true;
-               }
-
-               entity tmp_entity; // temporary entity
-               float d;
-               for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext) if(time >= tmp_entity.ons_overtime_damagedelay)
-               {
-                       // tmp_entity.max_health / 300 gives 5 minutes of overtime.
-                       // control points reduce the overtime duration.
-                       d = 1;
-                       entity e;
-                       for(e = ons_worldcplist; e; e = e.ons_worldcpnext)
-                       {
-                               if(DIFF_TEAM(e, tmp_entity))
-                               if(e.islinked)
-                                       d = d + 1;
-                       }
-
-                       if(autocvar_g_campaign && autocvar__campaign_testrun)
-                               d = d * tmp_entity.max_health;
-                       else
-                               d = d * tmp_entity.max_health / max(30, 60 * autocvar_timelimit_suddendeath);
-
-                       Damage(tmp_entity, tmp_entity, tmp_entity, d, DEATH_HURTTRIGGER.m_id, tmp_entity.origin, '0 0 0');
-
-                       tmp_entity.sprite.SendFlags |= 16;
-
-                       tmp_entity.ons_overtime_damagedelay = time + 1;
-               }
-       }
-       else { wpforenemy_announced = false; ons_stalemate = false; }
-
-       Onslaught_count_generators();
-
-       if(ONS_OWNED_GENERATORS_OK())
-               return 0;
-
-       int winner_team = Onslaught_GetWinnerTeam();
-
-       if(winner_team > 0)
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
-               TeamScore_AddToTeam(winner_team, ST_ONS_CAPS, +1);
-       }
-       else if(winner_team == -1)
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_TIED);
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_TIED);
-       }
-
-       ons_stalemate = false;
-
-       play2all(SND(CTF_CAPTURE(winner_team)));
-
-       round_handler_Init(7, autocvar_g_onslaught_warmup, autocvar_g_onslaught_round_timelimit);
-
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               STAT(ROUNDLOST, it) = true;
-               it.player_blocked = true;
-
-               nades_Clear(it);
-       });
-
-       return 1;
-}
-
-bool Onslaught_CheckPlayers()
-{
-       return 1;
-}
-
-void Onslaught_RoundStart()
-{
-       entity tmp_entity;
-       FOREACH_CLIENT(IS_PLAYER(it), it.player_blocked = false);
-
-       for(tmp_entity = ons_worldcplist; tmp_entity; tmp_entity = tmp_entity.ons_worldcpnext)
-               tmp_entity.sprite.SendFlags |= 16;
-
-       for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
-               tmp_entity.sprite.SendFlags |= 16;
-}
-
-
-// ================
-// Bot player logic
-// ================
-
-// NOTE: LEGACY CODE, needs to be re-written!
-
-void havocbot_goalrating_ons_offenseitems(entity this, float ratingscale, vector org, float sradius)
-{
-       bool needarmor = false, needweapons = false;
-
-       // Needs armor/health?
-       if(this.health<100)
-               needarmor = true;
-
-       // Needs weapons?
-       int c = 0;
-       FOREACH(Weapons, it != WEP_Null, {
-               if(this.weapons & (it.m_wepset))
-               if(++c >= 4)
-                       break;
-       });
-
-       if(c<4)
-               needweapons = true;
-
-       if(!needweapons && !needarmor)
-               return;
-
-       LOG_DEBUG(this.netname, " needs weapons ", ftos(needweapons));
-       LOG_DEBUG(this.netname, " needs armor ", ftos(needarmor));
-
-       // See what is around
-       FOREACH_ENTITY_FLOAT(bot_pickup, true,
-       {
-               // gather health and armor only
-               if (it.solid)
-               if ( ((it.health || it.armorvalue) && needarmor) || (it.weapons && needweapons ) )
-               if (vdist(it.origin - org, <, sradius))
-               {
-                       int t = it.bot_pickupevalfunc(this, it);
-                       if (t > 0)
-                               navigation_routerating(this, it, t * ratingscale, 500);
-               }
-       });
-}
-
-void havocbot_role_ons_setrole(entity this, int role)
-{
-       LOG_DEBUG(this.netname," switched to ");
-       switch(role)
-       {
-               case HAVOCBOT_ONS_ROLE_DEFENSE:
-                       LOG_DEBUG("defense");
-                       this.havocbot_role = havocbot_role_ons_defense;
-                       this.havocbot_role_flags = HAVOCBOT_ONS_ROLE_DEFENSE;
-                       this.havocbot_role_timeout = 0;
-                       break;
-               case HAVOCBOT_ONS_ROLE_ASSISTANT:
-                       LOG_DEBUG("assistant");
-                       this.havocbot_role = havocbot_role_ons_assistant;
-                       this.havocbot_role_flags = HAVOCBOT_ONS_ROLE_ASSISTANT;
-                       this.havocbot_role_timeout = 0;
-                       break;
-               case HAVOCBOT_ONS_ROLE_OFFENSE:
-                       LOG_DEBUG("offense");
-                       this.havocbot_role = havocbot_role_ons_offense;
-                       this.havocbot_role_flags = HAVOCBOT_ONS_ROLE_OFFENSE;
-                       this.havocbot_role_timeout = 0;
-                       break;
-       }
-       LOG_DEBUG("");
-}
-
-void havocbot_goalrating_ons_controlpoints_attack(entity this, float ratingscale)
-{
-       entity cp, cp1, cp2, best, wp;
-       float radius, bestvalue;
-       int c;
-       bool found;
-
-       // Filter control points
-       for(cp2 = ons_worldcplist; cp2; cp2 = cp2.ons_worldcpnext)
-       {
-               cp2.wpcost = c = 0;
-               cp2.wpconsidered = false;
-
-               if(cp2.isshielded)
-                       continue;
-
-               // Ignore owned controlpoints
-               if(!(cp2.isgenneighbor[this.team] || cp2.iscpneighbor[this.team]))
-                       continue;
-
-               // Count team mates interested in this control point
-               // (easier and cleaner than keeping counters per cp and teams)
-               FOREACH_CLIENT(IS_PLAYER(it), {
-                       if(SAME_TEAM(it, this))
-                       if(it.havocbot_role_flags & HAVOCBOT_ONS_ROLE_OFFENSE)
-                       if(it.havocbot_ons_target == cp2)
-                               ++c;
-               });
-
-               // NOTE: probably decrease the cost of attackable control points
-               cp2.wpcost = c;
-               cp2.wpconsidered = true;
-       }
-
-       // We'll consider only the best case
-       bestvalue = 99999999999;
-       cp = NULL;
-       for(cp1 = ons_worldcplist; cp1; cp1 = cp1.ons_worldcpnext)
-       {
-               if (!cp1.wpconsidered)
-                       continue;
-
-               if(cp1.wpcost<bestvalue)
-               {
-                       bestvalue = cp1.wpcost;
-                       cp = cp1;
-                       this.havocbot_ons_target = cp1;
-               }
-       }
-
-       if (!cp)
-               return;
-
-       LOG_DEBUG(this.netname, " chose cp ranked ", ftos(bestvalue));
-
-       if(cp.goalentity)
-       {
-               // Should be attacked
-               // Rate waypoints near it
-               found = false;
-               best = NULL;
-               bestvalue = 99999999999;
-               for(radius=0; radius<1000 && !found; radius+=500)
-               {
-                       for(wp=findradius(cp.origin,radius); wp; wp=wp.chain)
-                       {
-                               if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
-                               if(wp.classname=="waypoint")
-                               if(checkpvs(wp.origin,cp))
-                               {
-                                       found = true;
-                                       if(wp.cnt<bestvalue)
-                                       {
-                                               best = wp;
-                                               bestvalue = wp.cnt;
-                                       }
-                               }
-                       }
-               }
-
-               if(best)
-               {
-                       navigation_routerating(this, best, ratingscale, 10000);
-                       best.cnt += 1;
-
-                       this.havocbot_attack_time = 0;
-                       if(checkpvs(this.view_ofs,cp))
-                       if(checkpvs(this.view_ofs,best))
-                               this.havocbot_attack_time = time + 2;
-               }
-               else
-               {
-                       navigation_routerating(this, cp, ratingscale, 10000);
-               }
-               LOG_DEBUG(this.netname, " found an attackable controlpoint at ", vtos(cp.origin));
-       }
-       else
-       {
-               // Should be touched
-               LOG_DEBUG(this.netname, " found a touchable controlpoint at ", vtos(cp.origin));
-               found = false;
-
-               // Look for auto generated waypoint
-               if (!bot_waypoints_for_items)
-               for (wp = findradius(cp.origin,100); wp; wp = wp.chain)
-               {
-                       if(wp.classname=="waypoint")
-                       {
-                               navigation_routerating(this, wp, ratingscale, 10000);
-                               found = true;
-                       }
-               }
-
-               // Nothing found, rate the controlpoint itself
-               if (!found)
-                       navigation_routerating(this, cp, ratingscale, 10000);
-       }
-}
-
-bool havocbot_goalrating_ons_generator_attack(entity this, float ratingscale)
-{
-       entity g, wp, bestwp;
-       bool found;
-       int best;
-
-       for(g = ons_worldgeneratorlist; g; g = g.ons_worldgeneratornext)
-       {
-               if(SAME_TEAM(g, this) || g.isshielded)
-                       continue;
-
-               // Should be attacked
-               // Rate waypoints near it
-               found = false;
-               bestwp = NULL;
-               best = 99999999999;
-
-               for(wp=findradius(g.origin,400); wp; wp=wp.chain)
-               {
-                       if(wp.classname=="waypoint")
-                       if(checkpvs(wp.origin,g))
-                       {
-                               found = true;
-                               if(wp.cnt<best)
-                               {
-                                       bestwp = wp;
-                                       best = wp.cnt;
-                               }
-                       }
-               }
-
-               if(bestwp)
-               {
-                       LOG_DEBUG("waypoints found around generator");
-                       navigation_routerating(this, bestwp, ratingscale, 10000);
-                       bestwp.cnt += 1;
-
-                       this.havocbot_attack_time = 0;
-                       if(checkpvs(this.view_ofs,g))
-                       if(checkpvs(this.view_ofs,bestwp))
-                               this.havocbot_attack_time = time + 5;
-
-                       return true;
-               }
-               else
-               {
-                       LOG_DEBUG("generator found without waypoints around");
-                       // if there aren't waypoints near the generator go straight to it
-                       navigation_routerating(this, g, ratingscale, 10000);
-                       this.havocbot_attack_time = 0;
-                       return true;
-               }
-       }
-       return false;
-}
-
-void havocbot_role_ons_offense(entity this)
-{
-       if(IS_DEAD(this))
-       {
-               this.havocbot_attack_time = 0;
-               havocbot_ons_reset_role(this);
-               return;
-       }
-
-       // Set the role timeout if necessary
-       if (!this.havocbot_role_timeout)
-               this.havocbot_role_timeout = time + 120;
-
-       if (time > this.havocbot_role_timeout)
-       {
-               havocbot_ons_reset_role(this);
-               return;
-       }
-
-       if(this.havocbot_attack_time>time)
-               return;
-
-       if (this.bot_strategytime < time)
-       {
-               navigation_goalrating_start(this);
-               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 650);
-               if(!havocbot_goalrating_ons_generator_attack(this, 20000))
-                       havocbot_goalrating_ons_controlpoints_attack(this, 20000);
-               havocbot_goalrating_ons_offenseitems(this, 10000, this.origin, 10000);
-               navigation_goalrating_end(this);
-
-               this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
-       }
-}
-
-void havocbot_role_ons_assistant(entity this)
-{
-       havocbot_ons_reset_role(this);
-}
-
-void havocbot_role_ons_defense(entity this)
-{
-       havocbot_ons_reset_role(this);
-}
-
-void havocbot_ons_reset_role(entity this)
-{
-       if(IS_DEAD(this))
-               return;
-
-       this.havocbot_ons_target = NULL;
-
-       // TODO: Defend control points or generator if necessary
-
-       havocbot_role_ons_setrole(this, HAVOCBOT_ONS_ROLE_OFFENSE);
-}
-
-
-/*
- * Find control point or generator owned by the same team self which is nearest to pos
- * if max_dist is positive, only control points within this range will be considered
- */
-entity ons_Nearest_ControlPoint(entity this, vector pos, float max_dist)
-{
-       entity closest_target = NULL;
-       FOREACH_ENTITY_CLASS("onslaught_controlpoint", true,
-       {
-               if(SAME_TEAM(it, this))
-               if(it.iscaptured)
-               if(max_dist <= 0 || vdist(it.origin - pos, <=, max_dist))
-               if(vlen2(it.origin - pos) <= vlen2(closest_target.origin - pos) || closest_target == NULL)
-                       closest_target = it;
-       });
-       FOREACH_ENTITY_CLASS("onslaught_generator", true,
-       {
-               if(SAME_TEAM(it, this))
-               if(max_dist <= 0 || vdist(it.origin - pos, <, max_dist))
-               if(vlen2(it.origin - pos) <= vlen2(closest_target.origin - pos) || closest_target == NULL)
-                       closest_target = it;
-       });
-
-       return closest_target;
-}
-
-/*
- * Find control point or generator owned by the same team self which is nearest to pos
- * if max_dist is positive, only control points within this range will be considered
- * This function only check distances on the XY plane, disregarding Z
- */
-entity ons_Nearest_ControlPoint_2D(entity this, vector pos, float max_dist)
-{
-       entity closest_target = NULL;
-       vector delta;
-       float smallest_distance = 0, distance;
-
-       FOREACH_ENTITY_CLASS("onslaught_controlpoint", true,
-       {
-               delta = it.origin - pos;
-               delta_z = 0;
-               distance = vlen(delta);
-
-               if(SAME_TEAM(it, this))
-               if(it.iscaptured)
-               if(max_dist <= 0 || distance <= max_dist)
-               if(closest_target == NULL || distance <= smallest_distance )
-               {
-                       closest_target = it;
-                       smallest_distance = distance;
-               }
-       });
-       FOREACH_ENTITY_CLASS("onslaught_generator", true,
-       {
-               delta = it.origin - pos;
-               delta_z = 0;
-               distance = vlen(delta);
-
-               if(SAME_TEAM(it, this))
-               if(max_dist <= 0 || distance <= max_dist)
-               if(closest_target == NULL || distance <= smallest_distance )
-               {
-                       closest_target = it;
-                       smallest_distance = distance;
-               }
-       });
-
-       return closest_target;
-}
-/**
- * find the number of control points and generators in the same team as this
- */
-int ons_Count_SelfControlPoints(entity this)
-{
-       int n = 0;
-       FOREACH_ENTITY_CLASS("onslaught_controlpoint", true,
-       {
-               if(SAME_TEAM(it, this))
-               if(it.iscaptured)
-                       n++;
-       });
-       FOREACH_ENTITY_CLASS("onslaught_generator", true,
-       {
-               if(SAME_TEAM(it, this))
-                       n++;
-       });
-       return n;
-}
-
-/**
- * Teleport player to a random position near tele_target
- * if tele_effects is true, teleport sound+particles are created
- * return false on failure
- */
-bool ons_Teleport(entity player, entity tele_target, float range, bool tele_effects)
-{
-       if ( !tele_target )
-               return false;
-
-       int i;
-       vector loc;
-       float theta;
-       // narrow the range for each iteration to increase chances that a spawnpoint
-       // can be found even if there's little room around the control point
-       float iteration_scale = 1;
-       for(i = 0; i < 16; ++i)
-       {
-               iteration_scale -= i / 16;
-               theta = random() * 2 * M_PI;
-               loc_y = sin(theta);
-               loc_x = cos(theta);
-               loc_z = 0;
-               loc *= random() * range * iteration_scale;
-
-               loc += tele_target.origin + '0 0 128' * iteration_scale;
-
-               tracebox(loc, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), loc, MOVE_NORMAL, player);
-               if(trace_fraction == 1.0 && !trace_startsolid)
-               {
-                       traceline(tele_target.origin, loc, MOVE_NOMONSTERS, tele_target); // double check to make sure we're not spawning outside the NULL
-                       if(trace_fraction == 1.0 && !trace_startsolid)
-                       {
-                               if ( tele_effects )
-                               {
-                                       Send_Effect(EFFECT_TELEPORT, player.origin, '0 0 0', 1);
-                                       sound (player, CH_TRIGGER, SND_TELEPORT, VOL_BASE, ATTEN_NORM);
-                               }
-                               setorigin(player, loc);
-                               player.angles = '0 1 0' * ( theta * RAD2DEG + 180 );
-                               makevectors(player.angles);
-                               player.fixangle = true;
-                               player.teleport_antispam = time + autocvar_g_onslaught_teleport_wait;
-
-                               if ( tele_effects )
-                                       Send_Effect(EFFECT_TELEPORT, player.origin + v_forward * 32, '0 0 0', 1);
-                               return true;
-                       }
-               }
-       }
-
-       return false;
-}
-
-// ==============
-// Hook Functions
-// ==============
-
-MUTATOR_HOOKFUNCTION(ons, reset_map_global)
-{
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               STAT(ROUNDLOST, it) = false;
-               it.ons_deathloc = '0 0 0';
-               PutClientInServer(it);
-       });
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, ClientDisconnect)
-{
-       entity player = M_ARGV(0, entity);
-
-       player.ons_deathloc = '0 0 0';
-}
-
-MUTATOR_HOOKFUNCTION(ons, MakePlayerObserver)
-{
-       entity player = M_ARGV(0, entity);
-
-       player.ons_deathloc = '0 0 0';
-}
-
-MUTATOR_HOOKFUNCTION(ons, PlayerSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(!round_handler_IsRoundStarted())
-       {
-               player.player_blocked = true;
-               return false;
-       }
-
-       entity l;
-       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
-       {
-               l.sprite.SendFlags |= 16;
-       }
-       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
-       {
-               l.sprite.SendFlags |= 16;
-       }
-
-       if(ons_stalemate) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_OVERTIME_CONTROLPOINT); }
-
-       if ( autocvar_g_onslaught_spawn_choose )
-       if ( player.ons_spawn_by )
-       if ( ons_Teleport(player,player.ons_spawn_by,autocvar_g_onslaught_teleport_radius,false) )
-       {
-               player.ons_spawn_by = NULL;
-               return false;
-       }
-
-       if(autocvar_g_onslaught_spawn_at_controlpoints)
-       if(random() <= autocvar_g_onslaught_spawn_at_controlpoints_chance)
-       {
-               float random_target = autocvar_g_onslaught_spawn_at_controlpoints_random;
-               entity tmp_entity, closest_target = NULL;
-               vector spawn_loc = player.ons_deathloc;
-
-               // new joining player or round reset, don't bother checking
-               if(spawn_loc == '0 0 0') { return false; }
-
-               if(random_target) { RandomSelection_Init(); }
-
-               for(tmp_entity = ons_worldcplist; tmp_entity; tmp_entity = tmp_entity.ons_worldcpnext)
-               {
-                       if(SAME_TEAM(tmp_entity, player))
-                       if(random_target)
-                               RandomSelection_Add(tmp_entity, 0, string_null, 1, 1);
-                       else if(vlen2(tmp_entity.origin - spawn_loc) <= vlen2(closest_target.origin - spawn_loc) || closest_target == NULL)
-                               closest_target = tmp_entity;
-               }
-
-               if(random_target) { closest_target = RandomSelection_chosen_ent; }
-
-               if(closest_target)
-               {
-                       float i;
-                       vector loc;
-                       float iteration_scale = 1;
-                       for(i = 0; i < 10; ++i)
-                       {
-                               iteration_scale -= i / 10;
-                               loc = closest_target.origin + '0 0 96' * iteration_scale;
-                               loc += ('0 1 0' * random()) * 128 * iteration_scale;
-                               tracebox(loc, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), loc, MOVE_NORMAL, player);
-                               if(trace_fraction == 1.0 && !trace_startsolid)
-                               {
-                                       traceline(closest_target.origin, loc, MOVE_NOMONSTERS, closest_target); // double check to make sure we're not spawning outside the NULL
-                                       if(trace_fraction == 1.0 && !trace_startsolid)
-                                       {
-                                               setorigin(player, loc);
-                                               player.angles = normalize(loc - closest_target.origin) * RAD2DEG;
-                                               return false;
-                                       }
-                               }
-                       }
-               }
-       }
-
-       if(autocvar_g_onslaught_spawn_at_generator)
-       if(random() <= autocvar_g_onslaught_spawn_at_generator_chance)
-       {
-               float random_target = autocvar_g_onslaught_spawn_at_generator_random;
-               entity tmp_entity, closest_target = NULL;
-               vector spawn_loc = player.ons_deathloc;
-
-               // new joining player or round reset, don't bother checking
-               if(spawn_loc == '0 0 0') { return false; }
-
-               if(random_target) { RandomSelection_Init(); }
-
-               for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
-               {
-                       if(random_target)
-                               RandomSelection_Add(tmp_entity, 0, string_null, 1, 1);
-                       else
-                       {
-                               if(SAME_TEAM(tmp_entity, player))
-                               if(vlen2(tmp_entity.origin - spawn_loc) <= vlen2(closest_target.origin - spawn_loc) || closest_target == NULL)
-                                       closest_target = tmp_entity;
-                       }
-               }
-
-               if(random_target) { closest_target = RandomSelection_chosen_ent; }
-
-               if(closest_target)
-               {
-                       float i;
-                       vector loc;
-                       float iteration_scale = 1;
-                       for(i = 0; i < 10; ++i)
-                       {
-                               iteration_scale -= i / 10;
-                               loc = closest_target.origin + '0 0 128' * iteration_scale;
-                               loc += ('0 1 0' * random()) * 256 * iteration_scale;
-                               tracebox(loc, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), loc, MOVE_NORMAL, player);
-                               if(trace_fraction == 1.0 && !trace_startsolid)
-                               {
-                                       traceline(closest_target.origin, loc, MOVE_NOMONSTERS, closest_target); // double check to make sure we're not spawning outside the NULL
-                                       if(trace_fraction == 1.0 && !trace_startsolid)
-                                       {
-                                               setorigin(player, loc);
-                                               player.angles = normalize(loc - closest_target.origin) * RAD2DEG;
-                                               return false;
-                                       }
-                               }
-                       }
-               }
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, PlayerDies)
-{
-       entity frag_target = M_ARGV(2, entity);
-
-       frag_target.ons_deathloc = frag_target.origin;
-       entity l;
-       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
-       {
-               l.sprite.SendFlags |= 16;
-       }
-       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
-       {
-               l.sprite.SendFlags |= 16;
-       }
-
-       if ( autocvar_g_onslaught_spawn_choose )
-       if ( ons_Count_SelfControlPoints(frag_target) > 1 )
-               stuffcmd(frag_target, "qc_cmd_cl hud clickradar\n");
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, MonsterMove)
-{
-       entity mon = M_ARGV(0, entity);
-
-       entity e = find(NULL, targetname, mon.target);
-       if (e != NULL)
-               mon.team = e.team;
-}
-
-void ons_MonsterSpawn_Delayed(entity this)
-{
-       entity own = this.owner;
-
-       if(!own) { delete(this); return; }
-
-       if(own.targetname)
-       {
-               entity e = find(NULL, target, own.targetname);
-               if(e != NULL)
-               {
-                       own.team = e.team;
-
-                       own.use(own, e, NULL);
-               }
-       }
-
-       delete(this);
-}
-
-MUTATOR_HOOKFUNCTION(ons, MonsterSpawn)
-{
-       entity mon = M_ARGV(0, entity);
-
-       entity e = spawn();
-       e.owner = mon;
-       InitializeEntity(e, ons_MonsterSpawn_Delayed, INITPRIO_FINDTARGET);
-}
-
-void ons_TurretSpawn_Delayed(entity this)
-{
-       entity own = this.owner;
-
-       if(!own) { delete(this); return; }
-
-       if(own.targetname)
-       {
-               entity e = find(NULL, target, own.targetname);
-               if(e != NULL)
-               {
-                       own.team = e.team;
-                       own.active = ACTIVE_NOT;
-
-                       own.use(own, e, NULL);
-               }
-       }
-
-       delete(this);
-}
-
-MUTATOR_HOOKFUNCTION(ons, TurretSpawn)
-{
-       entity turret = M_ARGV(0, entity);
-
-       entity e = spawn();
-       e.owner = turret;
-       InitializeEntity(e, ons_TurretSpawn_Delayed, INITPRIO_FINDTARGET);
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, HavocBot_ChooseRole)
-{
-       entity bot = M_ARGV(0, entity);
-
-       havocbot_ons_reset_role(bot);
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ons, GetTeamCount)
-{
-       // onslaught is special
-       for(entity tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
-       {
-               switch(tmp_entity.team)
-               {
-                       case NUM_TEAM_1: c1 = 0; break;
-                       case NUM_TEAM_2: c2 = 0; break;
-                       case NUM_TEAM_3: c3 = 0; break;
-                       case NUM_TEAM_4: c4 = 0; break;
-               }
-       }
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ons, SpectateCopy)
-{
-       entity spectatee = M_ARGV(0, entity);
-       entity client = M_ARGV(1, entity);
-
-       STAT(ROUNDLOST, client) = STAT(ROUNDLOST, spectatee); // make spectators see it too
-}
-
-MUTATOR_HOOKFUNCTION(ons, SV_ParseClientCommand)
-{
-       if(MUTATOR_RETURNVALUE) // command was already handled?
-               return false;
-
-       entity player = M_ARGV(0, entity);
-       string cmd_name = M_ARGV(1, string);
-       int cmd_argc = M_ARGV(2, int);
-
-       if ( cmd_name == "ons_spawn" )
-       {
-               vector pos = player.origin;
-               if(cmd_argc > 1)
-                       pos_x = stof(argv(1));
-               if(cmd_argc > 2)
-                       pos_y = stof(argv(2));
-               if(cmd_argc > 3)
-                       pos_z = stof(argv(3));
-
-               if ( IS_PLAYER(player) )
-               {
-                       if ( !STAT(FROZEN, player) )
-                       {
-                               entity source_point = ons_Nearest_ControlPoint(player, player.origin, autocvar_g_onslaught_teleport_radius);
-
-                               if ( !source_point && player.health > 0 )
-                               {
-                                       sprint(player, "\nYou need to be next to a control point\n");
-                                       return true;
-                               }
-
-
-                               entity closest_target = ons_Nearest_ControlPoint_2D(player, pos, autocvar_g_onslaught_click_radius);
-
-                               if ( closest_target == NULL )
-                               {
-                                       sprint(player, "\nNo control point found\n");
-                                       return true;
-                               }
-
-                               if ( player.health <= 0 )
-                               {
-                                       player.ons_spawn_by = closest_target;
-                                       player.respawn_flags = player.respawn_flags | RESPAWN_FORCE;
-                               }
-                               else
-                               {
-                                       if ( source_point == closest_target )
-                                       {
-                                               sprint(player, "\nTeleporting to the same point\n");
-                                               return true;
-                                       }
-
-                                       if ( !ons_Teleport(player,closest_target,autocvar_g_onslaught_teleport_radius,true) )
-                                               sprint(player, "\nUnable to teleport there\n");
-                               }
-
-                               return true;
-                       }
-
-                       sprint(player, "\nNo teleportation for you\n");
-               }
-
-               return true;
-       }
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, PlayerUseKey)
-{
-       if(MUTATOR_RETURNVALUE || gameover) { return false; }
-
-       entity player = M_ARGV(0, entity);
-
-       if((time > player.teleport_antispam) && (!IS_DEAD(player)) && !player.vehicle)
-       {
-               entity source_point = ons_Nearest_ControlPoint(player, player.origin, autocvar_g_onslaught_teleport_radius);
-               if ( source_point )
-               {
-                       stuffcmd(player, "qc_cmd_cl hud clickradar\n");
-                       return true;
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ons, PlayHitsound)
-{
-       entity frag_victim = M_ARGV(0, entity);
-
-       return (frag_victim.classname == "onslaught_generator" && !frag_victim.isshielded)
-               || (frag_victim.classname == "onslaught_controlpoint_icon" && !frag_victim.owner.isshielded);
-}
-
-MUTATOR_HOOKFUNCTION(ons, SendWaypoint)
-{
-    entity wp = M_ARGV(0, entity);
-    entity to = M_ARGV(1, entity);
-    int sf = M_ARGV(2, int);
-    int wp_flag = M_ARGV(3, int);
-
-       if(sf & 16)
-       {
-               if(wp.owner.classname == "onslaught_controlpoint")
-               {
-                       entity wp_owner = wp.owner;
-                       entity e = WaypointSprite_getviewentity(to);
-                       if(SAME_TEAM(e, wp_owner) && wp_owner.goalentity.health >= wp_owner.goalentity.max_health) { wp_flag |= 2; }
-                       if(!ons_ControlPoint_Attackable(wp_owner, e.team)) { wp_flag |= 2; }
-               }
-               if(wp.owner.classname == "onslaught_generator")
-               {
-                       entity wp_owner = wp.owner;
-                       if(wp_owner.isshielded && wp_owner.health >= wp_owner.max_health) { wp_flag |= 2; }
-                       if(wp_owner.health <= 0) { wp_flag |= 2; }
-               }
-       }
-
-       M_ARGV(3, int) = wp_flag;
-}
-
-MUTATOR_HOOKFUNCTION(ons, TurretValidateTarget)
-{
-       entity turret_target = M_ARGV(1, entity);
-
-       if(substring(turret_target.classname, 0, 10) == "onslaught_") // don't attack onslaught targets, that's the player's job!
-       {
-               M_ARGV(3, float) = -3;
-               return true;
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, TurretThink)
-{
-    entity turret = M_ARGV(0, entity);
-
-       // ONS uses somewhat backwards linking.
-       if(turret.target)
-       {
-               entity e = find(NULL, targetname, turret.target);
-               if (e != NULL)
-                       turret.team = e.team;
-       }
-
-       if(turret.team != turret.tur_head.team)
-               turret_respawn(turret);
-}
-
-
-// ==========
-// Spawnfuncs
-// ==========
-
-/*QUAKED spawnfunc_onslaught_link (0 .5 .8) (-16 -16 -16) (16 16 16)
-  Link between control points.
-
-  This entity targets two different spawnfunc_onslaught_controlpoint or spawnfunc_onslaught_generator entities, and suppresses shielding on both if they are owned by different teams.
-
-keys:
-"target" - first control point.
-"target2" - second control point.
- */
-spawnfunc(onslaught_link)
-{
-       if(!g_onslaught) { delete(this); return; }
-
-       if (this.target == "" || this.target2 == "")
-               objerror(this, "target and target2 must be set\n");
-
-       this.ons_worldlinknext = ons_worldlinklist; // link into ons_worldlinklist
-       ons_worldlinklist = this;
-
-       InitializeEntity(this, ons_DelayedLinkSetup, INITPRIO_FINDTARGET);
-       Net_LinkEntity(this, false, 0, ons_Link_Send);
-}
-
-/*QUAKED spawnfunc_onslaught_controlpoint (0 .5 .8) (-32 -32 0) (32 32 128)
-  Control point. Be sure to give this enough clearance so that the shootable part has room to exist
-
-  This should link to an spawnfunc_onslaught_controlpoint entity or spawnfunc_onslaught_generator entity.
-
-keys:
-"targetname" - name that spawnfunc_onslaught_link entities will use to target this.
-"target" - target any entities that are tied to this control point, such as vehicles and buildable structure entities.
-"message" - name of this control point (should reflect the location in the map, such as "center bridge", "north tower", etc)
- */
-
-spawnfunc(onslaught_controlpoint)
-{
-       if(!g_onslaught) { delete(this); return; }
-
-       ons_ControlPoint_Setup(this);
-}
-
-/*QUAKED spawnfunc_onslaught_generator (0 .5 .8) (-32 -32 -24) (32 32 64)
-  Base generator.
-
-  spawnfunc_onslaught_link entities can target this.
-
-keys:
-"team" - team that owns this generator (5 = red, 14 = blue, etc), MUST BE SET.
-"targetname" - name that spawnfunc_onslaught_link entities will use to target this.
- */
-spawnfunc(onslaught_generator)
-{
-       if(!g_onslaught) { delete(this); return; }
-       if(!this.team) { objerror(this, "team must be set"); }
-
-       ons_GeneratorSetup(this);
-}
-
-// scoreboard setup
-void ons_ScoreRules()
-{
-       CheckAllowedTeams(NULL);
-       int teams = 0;
-       if(c1 >= 0) teams |= BIT(0);
-       if(c2 >= 0) teams |= BIT(1);
-       if(c3 >= 0) teams |= BIT(2);
-       if(c4 >= 0) teams |= BIT(3);
-       ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, true);
-       ScoreInfo_SetLabel_TeamScore  (ST_ONS_CAPS,     "destroyed", SFL_SORT_PRIO_PRIMARY);
-       ScoreInfo_SetLabel_PlayerScore(SP_ONS_CAPS,    "caps",      SFL_SORT_PRIO_SECONDARY);
-       ScoreInfo_SetLabel_PlayerScore(SP_ONS_TAKES,    "takes",     0);
-       ScoreRules_basics_end();
-}
-
-void ons_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up
-{
-       ons_ScoreRules();
-
-       round_handler_Spawn(Onslaught_CheckPlayers, Onslaught_CheckWinner, Onslaught_RoundStart);
-       round_handler_Init(5, autocvar_g_onslaught_warmup, autocvar_g_onslaught_round_timelimit);
-}
-
-void ons_Initialize()
-{
-       g_onslaught = true;
-       ons_captureshield_force = autocvar_g_onslaught_shield_force;
-
-       InitializeEntity(NULL, ons_DelayedInit, INITPRIO_GAMETYPE);
-}
-
-#endif
+#include "onslaught.qh"
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/onslaught.qh b/qcsrc/common/gamemodes/gamemode/onslaught/onslaught.qh
new file mode 100644 (file)
index 0000000..c863e2f
--- /dev/null
@@ -0,0 +1,14 @@
+#pragma once
+
+REGISTER_NET_LINKED(ENT_CLIENT_GENERATOR)
+REGISTER_NET_LINKED(ENT_CLIENT_CONTROLPOINT_ICON)
+
+#ifdef SVQC
+IntrusiveList g_onsshields;
+STATIC_INIT(g_onsshields) { g_onsshields = IL_NEW(); }
+#endif
+
+#ifdef CSQC
+IntrusiveList g_onsgenerators;
+STATIC_INIT(g_onsgenerators) { g_onsgenerators = IL_NEW(); }
+#endif
index d76f0ea069998ecc00bb61ed2c593a18f9c1db91..d5437338e3fb47ac0432e6de3b027bd81a366eec 100644 (file)
@@ -1,10 +1,7 @@
-#ifndef CONTROLPOINT_H
-#define CONTROLPOINT_H
+#pragma once
 
 const vector CPICON_MIN = '-32 -32 -9';
 const vector CPICON_MAX = '32 32 25';
 
 const int CPSF_STATUS = 4;
 const int CPSF_SETUP = 8;
-
-#endif
index 003c2b1d6855f1f93fed3d1ae078dbf2e8c841b9..8356689e204d7a6910c7fafd670c630fe4adf00b 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef GENERATOR_H
-#define GENERATOR_H
+#pragma once
+
 const vector GENERATOR_MIN = '-52 -52 -14';
 const vector GENERATOR_MAX = '52 52 75';
 
@@ -7,4 +7,3 @@ const int GSF_STATUS = 4;
 const int GSF_SETUP = 8;
 
 bool generator_send(entity this, entity to, int sf);
-#endif
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc b/qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc
new file mode 100644 (file)
index 0000000..8e60bc3
--- /dev/null
@@ -0,0 +1,2141 @@
+#include "sv_onslaught.qh"
+#include "sv_controlpoint.qh"
+#include "sv_generator.qh"
+
+bool g_onslaught;
+
+float autocvar_g_onslaught_teleport_wait;
+bool autocvar_g_onslaught_spawn_at_controlpoints;
+bool autocvar_g_onslaught_spawn_at_generator;
+float autocvar_g_onslaught_cp_proxydecap;
+float autocvar_g_onslaught_cp_proxydecap_distance = 512;
+float autocvar_g_onslaught_cp_proxydecap_dps = 100;
+float autocvar_g_onslaught_spawn_at_controlpoints_chance = 0.5;
+float autocvar_g_onslaught_spawn_at_controlpoints_random;
+float autocvar_g_onslaught_spawn_at_generator_chance;
+float autocvar_g_onslaught_spawn_at_generator_random;
+float autocvar_g_onslaught_cp_buildhealth;
+float autocvar_g_onslaught_cp_buildtime;
+float autocvar_g_onslaught_cp_health;
+float autocvar_g_onslaught_cp_regen;
+float autocvar_g_onslaught_gen_health;
+float autocvar_g_onslaught_shield_force = 100;
+float autocvar_g_onslaught_allow_vehicle_touch;
+float autocvar_g_onslaught_round_timelimit;
+float autocvar_g_onslaught_warmup;
+float autocvar_g_onslaught_teleport_radius;
+float autocvar_g_onslaught_spawn_choose;
+float autocvar_g_onslaught_click_radius;
+
+void FixSize(entity e);
+
+// =======================
+// CaptureShield Functions
+// =======================
+
+bool ons_CaptureShield_Customize(entity this, entity client)
+{
+       entity e = WaypointSprite_getviewentity(client);
+
+       if(!this.enemy.isshielded && (ons_ControlPoint_Attackable(this.enemy, e.team) > 0 || this.enemy.classname != "onslaught_controlpoint")) { return false; }
+       if(SAME_TEAM(this, e)) { return false; }
+
+       return true;
+}
+
+void ons_CaptureShield_Touch(entity this, entity toucher)
+{
+       if(!this.enemy.isshielded && (ons_ControlPoint_Attackable(this.enemy, toucher.team) > 0 || this.enemy.classname != "onslaught_controlpoint")) { return; }
+       if(!IS_PLAYER(toucher)) { return; }
+       if(SAME_TEAM(toucher, this)) { return; }
+
+       vector mymid = (this.absmin + this.absmax) * 0.5;
+       vector theirmid = (toucher.absmin + toucher.absmax) * 0.5;
+
+       Damage(toucher, this, this, 0, DEATH_HURTTRIGGER.m_id, mymid, normalize(theirmid - mymid) * ons_captureshield_force);
+
+       if(IS_REAL_CLIENT(toucher))
+       {
+               play2(toucher, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
+
+               if(this.enemy.classname == "onslaught_generator")
+                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_GENERATOR_SHIELDED);
+               else
+                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_CONTROLPOINT_SHIELDED);
+       }
+}
+
+void ons_CaptureShield_Reset(entity this)
+{
+       this.colormap = this.enemy.colormap;
+       this.team = this.enemy.team;
+}
+
+void ons_CaptureShield_Spawn(entity generator, bool is_generator)
+{
+       entity shield = new(ons_captureshield);
+       IL_PUSH(g_onsshields, shield);
+
+       shield.enemy = generator;
+       shield.team = generator.team;
+       shield.colormap = generator.colormap;
+       shield.reset = ons_CaptureShield_Reset;
+       settouch(shield, ons_CaptureShield_Touch);
+       setcefc(shield, ons_CaptureShield_Customize);
+       shield.effects = EF_ADDITIVE;
+       set_movetype(shield, MOVETYPE_NOCLIP);
+       shield.solid = SOLID_TRIGGER;
+       shield.avelocity = '7 0 11';
+       shield.scale = 1;
+       shield.model = ((is_generator) ? "models/onslaught/generator_shield.md3" : "models/onslaught/controlpoint_shield.md3");
+
+       precache_model(shield.model);
+       setorigin(shield, generator.origin);
+       _setmodel(shield, shield.model);
+       setsize(shield, shield.scale * shield.mins, shield.scale * shield.maxs);
+}
+
+
+// ==========
+// Junk Pile
+// ==========
+
+void setmodel_fixsize(entity e, Model m)
+{
+       setmodel(e, m);
+       FixSize(e);
+}
+
+void onslaught_updatelinks()
+{
+       entity l;
+       // first check if the game has ended
+       LOG_DEBUG("--- updatelinks ---");
+       // mark generators as being shielded and networked
+       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
+       {
+               if (l.iscaptured)
+                       LOG_DEBUG(etos(l), " (generator) belongs to team ", ftos(l.team));
+               else
+                       LOG_DEBUG(etos(l), " (generator) is destroyed");
+               l.islinked = l.iscaptured;
+               l.isshielded = l.iscaptured;
+               l.sprite.SendFlags |= 16;
+       }
+       // mark points as shielded and not networked
+       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
+       {
+               l.islinked = false;
+               l.isshielded = true;
+               int i;
+               for(i = 0; i < 17; ++i) { l.isgenneighbor[i] = false; l.iscpneighbor[i] = false; }
+               LOG_DEBUG(etos(l), " (point) belongs to team ", ftos(l.team));
+               l.sprite.SendFlags |= 16;
+       }
+       // flow power outward from the generators through the network
+       bool stop = false;
+       while (!stop)
+       {
+               stop = true;
+               for(l = ons_worldlinklist; l; l = l.ons_worldlinknext)
+               {
+                       // if both points are captured by the same team, and only one of
+                       // them is powered, mark the other one as powered as well
+                       if (l.enemy.iscaptured && l.goalentity.iscaptured)
+                               if (l.enemy.islinked != l.goalentity.islinked)
+                                       if(SAME_TEAM(l.enemy, l.goalentity))
+                                       {
+                                               if (!l.goalentity.islinked)
+                                               {
+                                                       stop = false;
+                                                       l.goalentity.islinked = true;
+                                                       LOG_DEBUG(etos(l), " (link) is marking ", etos(l.goalentity), " (point) because its team matches ", etos(l.enemy), " (point)");
+                                               }
+                                               else if (!l.enemy.islinked)
+                                               {
+                                                       stop = false;
+                                                       l.enemy.islinked = true;
+                                                       LOG_DEBUG(etos(l), " (link) is marking ", etos(l.enemy), " (point) because its team matches ", etos(l.goalentity), " (point)");
+                                               }
+                                       }
+               }
+       }
+       // now that we know which points are powered we can mark their neighbors
+       // as unshielded if team differs
+       for(l = ons_worldlinklist; l; l = l.ons_worldlinknext)
+       {
+               if (l.goalentity.islinked)
+               {
+                       if(DIFF_TEAM(l.goalentity, l.enemy))
+                       {
+                               LOG_DEBUG(etos(l), " (link) is unshielding ", etos(l.enemy), " (point) because its team does not match ", etos(l.goalentity), " (point)");
+                               l.enemy.isshielded = false;
+                       }
+                       if(l.goalentity.classname == "onslaught_generator")
+                               l.enemy.isgenneighbor[l.goalentity.team] = true;
+                       else
+                               l.enemy.iscpneighbor[l.goalentity.team] = true;
+               }
+               if (l.enemy.islinked)
+               {
+                       if(DIFF_TEAM(l.goalentity, l.enemy))
+                       {
+                               LOG_DEBUG(etos(l), " (link) is unshielding ", etos(l.goalentity), " (point) because its team does not match ", etos(l.enemy), " (point)");
+                               l.goalentity.isshielded = false;
+                       }
+                       if(l.enemy.classname == "onslaught_generator")
+                               l.goalentity.isgenneighbor[l.enemy.team] = true;
+                       else
+                               l.goalentity.iscpneighbor[l.enemy.team] = true;
+               }
+       }
+       // now update the generators
+       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
+       {
+               if (l.isshielded)
+               {
+                       LOG_DEBUG(etos(l), " (generator) is shielded");
+                       l.takedamage = DAMAGE_NO;
+                       if(l.bot_attack)
+                               IL_REMOVE(g_bot_targets, l);
+                       l.bot_attack = false;
+               }
+               else
+               {
+                       LOG_DEBUG(etos(l), " (generator) is not shielded");
+                       l.takedamage = DAMAGE_AIM;
+                       if(!l.bot_attack)
+                               IL_PUSH(g_bot_targets, l);
+                       l.bot_attack = true;
+               }
+
+               ons_Generator_UpdateSprite(l);
+       }
+       // now update the takedamage and alpha variables on control point icons
+       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
+       {
+               if (l.isshielded)
+               {
+                       LOG_DEBUG(etos(l), " (point) is shielded");
+                       if (l.goalentity)
+                       {
+                               l.goalentity.takedamage = DAMAGE_NO;
+                               if(l.goalentity.bot_attack)
+                                       IL_REMOVE(g_bot_targets, l.goalentity);
+                               l.goalentity.bot_attack = false;
+                       }
+               }
+               else
+               {
+                       LOG_DEBUG(etos(l), " (point) is not shielded");
+                       if (l.goalentity)
+                       {
+                               l.goalentity.takedamage = DAMAGE_AIM;
+                               if(!l.goalentity.bot_attack)
+                                       IL_PUSH(g_bot_targets, l.goalentity);
+                               l.goalentity.bot_attack = true;
+                       }
+               }
+               ons_ControlPoint_UpdateSprite(l);
+       }
+       IL_EACH(g_onsshields, true,
+       {
+               it.team = it.enemy.team;
+               it.colormap = it.enemy.colormap;
+       });
+}
+
+
+// ===================
+// Main Link Functions
+// ===================
+
+bool ons_Link_Send(entity this, entity to, int sendflags)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_RADARLINK);
+       WriteByte(MSG_ENTITY, sendflags);
+       if(sendflags & 1)
+       {
+               WriteCoord(MSG_ENTITY, this.goalentity.origin_x);
+               WriteCoord(MSG_ENTITY, this.goalentity.origin_y);
+               WriteCoord(MSG_ENTITY, this.goalentity.origin_z);
+       }
+       if(sendflags & 2)
+       {
+               WriteCoord(MSG_ENTITY, this.enemy.origin_x);
+               WriteCoord(MSG_ENTITY, this.enemy.origin_y);
+               WriteCoord(MSG_ENTITY, this.enemy.origin_z);
+       }
+       if(sendflags & 4)
+       {
+               WriteByte(MSG_ENTITY, this.clientcolors); // which is goalentity's color + enemy's color * 16
+       }
+       return true;
+}
+
+void ons_Link_CheckUpdate(entity this)
+{
+       // TODO check if the two sides have moved (currently they won't move anyway)
+       float cc = 0, cc1 = 0, cc2 = 0;
+
+       if(this.goalentity.islinked || this.goalentity.iscaptured) { cc1 = (this.goalentity.team - 1) * 0x01; }
+       if(this.enemy.islinked || this.enemy.iscaptured) { cc2 = (this.enemy.team - 1) * 0x10; }
+
+       cc = cc1 + cc2;
+
+       if(cc != this.clientcolors)
+       {
+               this.clientcolors = cc;
+               this.SendFlags |= 4;
+       }
+
+       this.nextthink = time;
+}
+
+void ons_DelayedLinkSetup(entity this)
+{
+       this.goalentity = find(NULL, targetname, this.target);
+       this.enemy = find(NULL, targetname, this.target2);
+       if(!this.goalentity) { objerror(this, "can not find target\n"); }
+       if(!this.enemy) { objerror(this, "can not find target2\n"); }
+
+       LOG_DEBUG(etos(this.goalentity), " linked with ", etos(this.enemy));
+       this.SendFlags |= 3;
+       setthink(this, ons_Link_CheckUpdate);
+       this.nextthink = time;
+}
+
+
+// =============================
+// Main Control Point Functions
+// =============================
+
+int ons_ControlPoint_CanBeLinked(entity cp, int teamnumber)
+{
+       if(cp.isgenneighbor[teamnumber]) { return 2; }
+       if(cp.iscpneighbor[teamnumber]) { return 1; }
+
+       return 0;
+}
+
+int ons_ControlPoint_Attackable(entity cp, int teamnumber)
+       // -2: SAME TEAM, attackable by enemy!
+       // -1: SAME TEAM!
+       // 0: off limits
+       // 1: attack it
+       // 2: touch it
+       // 3: attack it (HIGH PRIO)
+       // 4: touch it (HIGH PRIO)
+{
+       int a;
+
+       if(cp.isshielded)
+       {
+               return 0;
+       }
+       else if(cp.goalentity)
+       {
+               // if there's already an icon built, nothing happens
+               if(cp.team == teamnumber)
+               {
+                       a = ons_ControlPoint_CanBeLinked(cp, teamnumber);
+                       if(a) // attackable by enemy?
+                               return -2; // EMERGENCY!
+                       return -1;
+               }
+               // we know it can be linked, so no need to check
+               // but...
+               a = ons_ControlPoint_CanBeLinked(cp, teamnumber);
+               if(a == 2) // near our generator?
+                       return 3; // EMERGENCY!
+               return 1;
+       }
+       else
+       {
+               // free point
+               if(ons_ControlPoint_CanBeLinked(cp, teamnumber))
+               {
+                       a = ons_ControlPoint_CanBeLinked(cp, teamnumber); // why was this here NUM_TEAM_1 + NUM_TEAM_2 - t
+                       if(a == 2)
+                               return 4; // GET THIS ONE NOW!
+                       else
+                               return 2; // TOUCH ME
+               }
+       }
+       return 0;
+}
+
+void ons_ControlPoint_Icon_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{
+       if(damage <= 0) { return; }
+
+       if (this.owner.isshielded)
+       {
+               // this is protected by a shield, so ignore the damage
+               if (time > this.pain_finished)
+                       if (IS_PLAYER(attacker))
+                       {
+                               play2(attacker, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
+                               this.pain_finished = time + 1;
+                               attacker.typehitsound += 1; // play both sounds (shield is way too quiet)
+                       }
+
+               return;
+       }
+
+       if(IS_PLAYER(attacker))
+       if(time - ons_notification_time[this.team] > 10)
+       {
+               play2team(this.team, SND(ONS_CONTROLPOINT_UNDERATTACK));
+               ons_notification_time[this.team] = time;
+       }
+
+       this.health = this.health - damage;
+       if(this.owner.iscaptured)
+               WaypointSprite_UpdateHealth(this.owner.sprite, this.health);
+       else
+               WaypointSprite_UpdateBuildFinished(this.owner.sprite, time + (this.max_health - this.health) / (this.count / ONS_CP_THINKRATE));
+       this.pain_finished = time + 1;
+       // particles on every hit
+       pointparticles(EFFECT_SPARKS, hitloc, force*-1, 1);
+       //sound on every hit
+       if (random() < 0.5)
+               sound(this, CH_TRIGGER, SND_ONS_HIT1, VOL_BASE+0.3, ATTEN_NORM);
+       else
+               sound(this, CH_TRIGGER, SND_ONS_HIT2, VOL_BASE+0.3, ATTEN_NORM);
+
+       if (this.health < 0)
+       {
+               sound(this, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
+               pointparticles(EFFECT_ROCKET_EXPLODE, this.origin, '0 0 0', 1);
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_ONSLAUGHT_CPDESTROYED), this.owner.message, attacker.netname);
+
+               PlayerScore_Add(attacker, SP_ONS_TAKES, 1);
+               PlayerScore_Add(attacker, SP_SCORE, 10);
+
+               this.owner.goalentity = NULL;
+               this.owner.islinked = false;
+               this.owner.iscaptured = false;
+               this.owner.team = 0;
+               this.owner.colormap = 1024;
+
+               WaypointSprite_UpdateMaxHealth(this.owner.sprite, 0);
+
+               onslaught_updatelinks();
+
+               // Use targets now (somebody make sure this is in the right place..)
+               SUB_UseTargets(this.owner, this, NULL);
+
+               this.owner.waslinked = this.owner.islinked;
+               if(this.owner.model != "models/onslaught/controlpoint_pad.md3")
+                       setmodel_fixsize(this.owner, MDL_ONS_CP_PAD1);
+               //setsize(this, '-32 -32 0', '32 32 8');
+
+               delete(this);
+       }
+
+       this.SendFlags |= CPSF_STATUS;
+}
+
+void ons_ControlPoint_Icon_Think(entity this)
+{
+       this.nextthink = time + ONS_CP_THINKRATE;
+
+       if(autocvar_g_onslaught_cp_proxydecap)
+       {
+               int _enemy_count = 0;
+               int _friendly_count = 0;
+
+               FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
+                       if(vdist(it.origin - this.origin, <, autocvar_g_onslaught_cp_proxydecap_distance))
+                       {
+                               if(SAME_TEAM(it, this))
+                                       ++_friendly_count;
+                               else
+                                       ++_enemy_count;
+                       }
+               });
+
+               _friendly_count = _friendly_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
+               _enemy_count = _enemy_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
+
+               this.health = bound(0, this.health + (_friendly_count - _enemy_count), this.max_health);
+               this.SendFlags |= CPSF_STATUS;
+               if(this.health <= 0)
+               {
+                       ons_ControlPoint_Icon_Damage(this, this, this, 1, 0, this.origin, '0 0 0');
+                       return;
+               }
+       }
+
+       if (time > this.pain_finished + 5)
+       {
+               if(this.health < this.max_health)
+               {
+                       this.health = this.health + this.count;
+                       if (this.health >= this.max_health)
+                               this.health = this.max_health;
+                       WaypointSprite_UpdateHealth(this.owner.sprite, this.health);
+               }
+       }
+
+       if(this.owner.islinked != this.owner.waslinked)
+       {
+               // unteam the spawnpoint if needed
+               int t = this.owner.team;
+               if(!this.owner.islinked)
+                       this.owner.team = 0;
+
+               SUB_UseTargets(this.owner, this, NULL);
+
+               this.owner.team = t;
+
+               this.owner.waslinked = this.owner.islinked;
+       }
+
+       // damaged fx
+       if(random() < 0.6 - this.health / this.max_health)
+       {
+               Send_Effect(EFFECT_ELECTRIC_SPARKS, this.origin + randompos('-10 -10 -20', '10 10 20'), '0 0 0', 1);
+
+               if(random() > 0.8)
+                       sound(this, CH_PAIN, SND_ONS_SPARK1, VOL_BASE, ATTEN_NORM);
+               else if (random() > 0.5)
+                       sound(this, CH_PAIN, SND_ONS_SPARK2, VOL_BASE, ATTEN_NORM);
+       }
+}
+
+void ons_ControlPoint_Icon_BuildThink(entity this)
+{
+       int a;
+
+       this.nextthink = time + ONS_CP_THINKRATE;
+
+       // only do this if there is power
+       a = ons_ControlPoint_CanBeLinked(this.owner, this.owner.team);
+       if(!a)
+               return;
+
+       this.health = this.health + this.count;
+
+       this.SendFlags |= CPSF_STATUS;
+
+       if (this.health >= this.max_health)
+       {
+               this.health = this.max_health;
+               this.count = autocvar_g_onslaught_cp_regen * ONS_CP_THINKRATE; // slow repair rate from now on
+               setthink(this, ons_ControlPoint_Icon_Think);
+               sound(this, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILT, VOL_BASE, ATTEN_NORM);
+               this.owner.iscaptured = true;
+               this.solid = SOLID_BBOX;
+
+               Send_Effect(EFFECT_CAP(this.owner.team), this.owner.origin, '0 0 0', 1);
+
+               WaypointSprite_UpdateMaxHealth(this.owner.sprite, this.max_health);
+               WaypointSprite_UpdateHealth(this.owner.sprite, this.health);
+
+               if(IS_PLAYER(this.owner.ons_toucher))
+               {
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ONSLAUGHT_CAPTURE, this.owner.ons_toucher.netname, this.owner.message);
+                       Send_Notification(NOTIF_ALL_EXCEPT, this.owner.ons_toucher, MSG_CENTER, APP_TEAM_NUM(this.owner.ons_toucher.team, CENTER_ONS_CAPTURE), this.owner.message);
+                       Send_Notification(NOTIF_ONE, this.owner.ons_toucher, MSG_CENTER, CENTER_ONS_CAPTURE, this.owner.message);
+                       PlayerScore_Add(this.owner.ons_toucher, SP_ONS_CAPS, 1);
+                       PlayerTeamScore_AddScore(this.owner.ons_toucher, 10);
+               }
+
+               this.owner.ons_toucher = NULL;
+
+               onslaught_updatelinks();
+
+               // Use targets now (somebody make sure this is in the right place..)
+               SUB_UseTargets(this.owner, this, NULL);
+
+               this.SendFlags |= CPSF_SETUP;
+       }
+       if(this.owner.model != MDL_ONS_CP_PAD2.model_str())
+               setmodel_fixsize(this.owner, MDL_ONS_CP_PAD2);
+
+       if(random() < 0.9 - this.health / this.max_health)
+               Send_Effect(EFFECT_RAGE, this.origin + 10 * randomvec(), '0 0 -1', 1);
+}
+
+void onslaught_controlpoint_icon_link(entity e, void(entity this) spawnproc);
+
+void ons_ControlPoint_Icon_Spawn(entity cp, entity player)
+{
+       entity e = new(onslaught_controlpoint_icon);
+
+       setsize(e, CPICON_MIN, CPICON_MAX);
+       setorigin(e, cp.origin + CPICON_OFFSET);
+
+       e.owner = cp;
+       e.max_health = autocvar_g_onslaught_cp_health;
+       e.health = autocvar_g_onslaught_cp_buildhealth;
+       e.solid = SOLID_NOT;
+       e.takedamage = DAMAGE_AIM;
+       e.bot_attack = true;
+       IL_PUSH(g_bot_targets, e);
+       e.event_damage = ons_ControlPoint_Icon_Damage;
+       e.team = player.team;
+       e.colormap = 1024 + (e.team - 1) * 17;
+       e.count = (e.max_health - e.health) * ONS_CP_THINKRATE / autocvar_g_onslaught_cp_buildtime; // how long it takes to build
+
+       sound(e, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILD, VOL_BASE, ATTEN_NORM);
+
+       cp.goalentity = e;
+       cp.team = e.team;
+       cp.colormap = e.colormap;
+
+       Send_Effect(EFFECT_FLAG_TOUCH(player.team), e.origin, '0 0 0', 1);
+
+       WaypointSprite_UpdateBuildFinished(cp.sprite, time + (e.max_health - e.health) / (e.count / ONS_CP_THINKRATE));
+       WaypointSprite_UpdateRule(cp.sprite,cp.team,SPRITERULE_TEAMPLAY);
+       cp.sprite.SendFlags |= 16;
+
+       onslaught_controlpoint_icon_link(e, ons_ControlPoint_Icon_BuildThink);
+}
+
+entity ons_ControlPoint_Waypoint(entity e)
+{
+       if(e.team)
+       {
+               int a = ons_ControlPoint_Attackable(e, e.team);
+
+               if(a == -2) { return WP_OnsCPDefend; } // defend now
+               if(a == -1 || a == 1 || a == 2) { return WP_OnsCP; } // touch
+               if(a == 3 || a == 4) { return WP_OnsCPAttack; } // attack
+       }
+       else
+               return WP_OnsCP;
+
+       return WP_Null;
+}
+
+void ons_ControlPoint_UpdateSprite(entity e)
+{
+       entity s1 = ons_ControlPoint_Waypoint(e);
+       WaypointSprite_UpdateSprites(e.sprite, s1, s1, s1);
+
+       bool sh;
+       sh = !(ons_ControlPoint_CanBeLinked(e, NUM_TEAM_1) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_2) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_3) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_4));
+
+       if(e.lastteam != e.team + 2 || e.lastshielded != sh || e.iscaptured != e.lastcaptured)
+       {
+               if(e.iscaptured) // don't mess up build bars!
+               {
+                       if(sh)
+                       {
+                               WaypointSprite_UpdateMaxHealth(e.sprite, 0);
+                       }
+                       else
+                       {
+                               WaypointSprite_UpdateMaxHealth(e.sprite, e.goalentity.max_health);
+                               WaypointSprite_UpdateHealth(e.sprite, e.goalentity.health);
+                       }
+               }
+               if(e.lastshielded)
+               {
+                       if(e.team)
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, 0.5 * colormapPaletteColor(e.team - 1, false));
+                       else
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.5 0.5 0.5');
+               }
+               else
+               {
+                       if(e.team)
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, colormapPaletteColor(e.team - 1, false));
+                       else
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.75 0.75 0.75');
+               }
+               WaypointSprite_Ping(e.sprite);
+
+               e.lastteam = e.team + 2;
+               e.lastshielded = sh;
+               e.lastcaptured = e.iscaptured;
+       }
+}
+
+void ons_ControlPoint_Touch(entity this, entity toucher)
+{
+       int attackable;
+
+       if(IS_VEHICLE(toucher) && toucher.owner)
+       if(autocvar_g_onslaught_allow_vehicle_touch)
+               toucher = toucher.owner;
+       else
+               return;
+
+       if(!IS_PLAYER(toucher)) { return; }
+       if(STAT(FROZEN, toucher)) { return; }
+       if(IS_DEAD(toucher)) { return; }
+
+       if ( SAME_TEAM(this,toucher) )
+       if ( this.iscaptured )
+       {
+               if(time <= toucher.teleport_antispam)
+                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT_ANTISPAM, rint(toucher.teleport_antispam - time));
+               else
+                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT);
+       }
+
+       attackable = ons_ControlPoint_Attackable(this, toucher.team);
+       if(attackable != 2 && attackable != 4)
+               return;
+       // we've verified that this player has a legitimate claim to this point,
+       // so start building the captured point icon (which only captures this
+       // point if it successfully builds without being destroyed first)
+       ons_ControlPoint_Icon_Spawn(this, toucher);
+
+       this.ons_toucher = toucher;
+
+       onslaught_updatelinks();
+}
+
+void ons_ControlPoint_Think(entity this)
+{
+       this.nextthink = time + ONS_CP_THINKRATE;
+       CSQCMODEL_AUTOUPDATE(this);
+}
+
+void ons_ControlPoint_Reset(entity this)
+{
+       if(this.goalentity)
+               delete(this.goalentity);
+
+       this.goalentity = NULL;
+       this.team = 0;
+       this.colormap = 1024;
+       this.iscaptured = false;
+       this.islinked = false;
+       this.isshielded = true;
+       setthink(this, ons_ControlPoint_Think);
+       this.ons_toucher = NULL;
+       this.nextthink = time + ONS_CP_THINKRATE;
+       setmodel_fixsize(this, MDL_ONS_CP_PAD1);
+
+       WaypointSprite_UpdateMaxHealth(this.sprite, 0);
+       WaypointSprite_UpdateRule(this.sprite,this.team,SPRITERULE_TEAMPLAY);
+
+       onslaught_updatelinks();
+
+       SUB_UseTargets(this, this, NULL); // to reset the structures, playerspawns etc.
+
+       CSQCMODEL_AUTOUPDATE(this);
+}
+
+void ons_DelayedControlPoint_Setup(entity this)
+{
+       onslaught_updatelinks();
+
+       // captureshield setup
+       ons_CaptureShield_Spawn(this, false);
+
+       CSQCMODEL_AUTOINIT(this);
+}
+
+void ons_ControlPoint_Setup(entity cp)
+{
+       // main setup
+       cp.ons_worldcpnext = ons_worldcplist; // link control point into ons_worldcplist
+       ons_worldcplist = cp;
+
+       cp.netname = "Control point";
+       cp.team = 0;
+       cp.solid = SOLID_BBOX;
+       set_movetype(cp, MOVETYPE_NONE);
+       settouch(cp, ons_ControlPoint_Touch);
+       setthink(cp, ons_ControlPoint_Think);
+       cp.nextthink = time + ONS_CP_THINKRATE;
+       cp.reset = ons_ControlPoint_Reset;
+       cp.colormap = 1024;
+       cp.iscaptured = false;
+       cp.islinked = false;
+       cp.isshielded = true;
+
+       if(cp.message == "") { cp.message = "a"; }
+
+       // appearence
+       setmodel_fixsize(cp, MDL_ONS_CP_PAD1);
+
+       // control point placement
+       if((cp.spawnflags & 1) || cp.noalign) // don't drop to floor, just stay at fixed location
+       {
+               cp.noalign = true;
+               set_movetype(cp, MOVETYPE_NONE);
+       }
+       else // drop to floor, automatically find a platform and set that as spawn origin
+       {
+               setorigin(cp, cp.origin + '0 0 20');
+               cp.noalign = false;
+               droptofloor(cp);
+               set_movetype(cp, MOVETYPE_TOSS);
+       }
+
+       // waypointsprites
+       WaypointSprite_SpawnFixed(WP_Null, cp.origin + CPGEN_WAYPOINT_OFFSET, cp, sprite, RADARICON_NONE);
+       WaypointSprite_UpdateRule(cp.sprite, cp.team, SPRITERULE_TEAMPLAY);
+
+       InitializeEntity(cp, ons_DelayedControlPoint_Setup, INITPRIO_SETLOCATION);
+}
+
+
+// =========================
+// Main Generator Functions
+// =========================
+
+entity ons_Generator_Waypoint(entity e)
+{
+       if (e.isshielded)
+               return WP_OnsGenShielded;
+       return WP_OnsGen;
+}
+
+void ons_Generator_UpdateSprite(entity e)
+{
+       entity s1 = ons_Generator_Waypoint(e);
+       WaypointSprite_UpdateSprites(e.sprite, s1, s1, s1);
+
+       if(e.lastteam != e.team + 2 || e.lastshielded != e.isshielded)
+       {
+               e.lastteam = e.team + 2;
+               e.lastshielded = e.isshielded;
+               if(e.lastshielded)
+               {
+                       if(e.team)
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, 0.5 * colormapPaletteColor(e.team - 1, false));
+                       else
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.5 0.5 0.5');
+               }
+               else
+               {
+                       if(e.team)
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, colormapPaletteColor(e.team - 1, false));
+                       else
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.75 0.75 0.75');
+               }
+               WaypointSprite_Ping(e.sprite);
+       }
+}
+
+void ons_GeneratorDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{
+       if(damage <= 0) { return; }
+       if(warmup_stage || gameover) { return; }
+       if(!round_handler_IsRoundStarted()) { return; }
+
+       if (attacker != this)
+       {
+               if (this.isshielded)
+               {
+                       // this is protected by a shield, so ignore the damage
+                       if (time > this.pain_finished)
+                               if (IS_PLAYER(attacker))
+                               {
+                                       play2(attacker, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
+                                       attacker.typehitsound += 1;
+                                       this.pain_finished = time + 1;
+                               }
+                       return;
+               }
+               if (time > this.pain_finished)
+               {
+                       this.pain_finished = time + 10;
+                       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && SAME_TEAM(it, this), Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_GENERATOR_UNDERATTACK));
+                       play2team(this.team, SND(ONS_GENERATOR_UNDERATTACK));
+               }
+       }
+       this.health = this.health - damage;
+       WaypointSprite_UpdateHealth(this.sprite, this.health);
+       // choose an animation frame based on health
+       this.frame = 10 * bound(0, (1 - this.health / this.max_health), 1);
+       // see if the generator is still functional, or dying
+       if (this.health > 0)
+       {
+               this.lasthealth = this.health;
+       }
+       else
+       {
+               if (attacker == this)
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_ONSLAUGHT_GENDESTROYED_OVERTIME));
+               else
+               {
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_ONSLAUGHT_GENDESTROYED));
+                       PlayerScore_Add(attacker, SP_SCORE, 100);
+               }
+               this.iscaptured = false;
+               this.islinked = false;
+               this.isshielded = false;
+               this.takedamage = DAMAGE_NO; // can't be hurt anymore
+               this.event_damage = func_null; // won't do anything if hurt
+               this.count = 0; // reset counter
+               setthink(this, func_null);
+               this.nextthink = 0;
+               //this.think(); // do the first explosion now
+
+               WaypointSprite_UpdateMaxHealth(this.sprite, 0);
+               WaypointSprite_Ping(this.sprite);
+               //WaypointSprite_Kill(this.sprite); // can't do this yet, code too poor
+
+               onslaught_updatelinks();
+       }
+
+       // Throw some flaming gibs on damage, more damage = more chance for gib
+       if(random() < damage/220)
+       {
+               sound(this, CH_TRIGGER, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+       }
+       else
+       {
+               // particles on every hit
+               Send_Effect(EFFECT_SPARKS, hitloc, force * -1, 1);
+
+               //sound on every hit
+               if (random() < 0.5)
+                       sound(this, CH_TRIGGER, SND_ONS_HIT1, VOL_BASE, ATTEN_NORM);
+               else
+                       sound(this, CH_TRIGGER, SND_ONS_HIT2, VOL_BASE, ATTEN_NORM);
+       }
+
+       this.SendFlags |= GSF_STATUS;
+}
+
+void ons_GeneratorThink(entity this)
+{
+       this.nextthink = time + GEN_THINKRATE;
+       if (!gameover)
+       {
+               if(!this.isshielded && this.wait < time)
+               {
+                       this.wait = time + 5;
+                       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
+                               if(SAME_TEAM(it, this))
+                               {
+                                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_ONS_NOTSHIELDED_TEAM);
+                                       soundto(MSG_ONE, it, CHAN_AUTO, SND(KH_ALARM), VOL_BASE, ATTEN_NONE);    // FIXME: unique sound?
+                               }
+                               else
+                                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_TEAM_NUM(this.team, CENTER_ONS_NOTSHIELDED));
+                       });
+               }
+       }
+}
+
+void ons_GeneratorReset(entity this)
+{
+       this.team = this.team_saved;
+       this.lasthealth = this.max_health = this.health = autocvar_g_onslaught_gen_health;
+       this.takedamage = DAMAGE_AIM;
+       this.bot_attack = true;
+       IL_PUSH(g_bot_targets, this);
+       this.iscaptured = true;
+       this.islinked = true;
+       this.isshielded = true;
+       this.event_damage = ons_GeneratorDamage;
+       setthink(this, ons_GeneratorThink);
+       this.nextthink = time + GEN_THINKRATE;
+
+       Net_LinkEntity(this, false, 0, generator_send);
+
+       this.SendFlags = GSF_SETUP; // just incase
+       this.SendFlags |= GSF_STATUS;
+
+       WaypointSprite_UpdateMaxHealth(this.sprite, this.max_health);
+       WaypointSprite_UpdateHealth(this.sprite, this.health);
+       WaypointSprite_UpdateRule(this.sprite,this.team,SPRITERULE_TEAMPLAY);
+
+       onslaught_updatelinks();
+}
+
+void ons_DelayedGeneratorSetup(entity this)
+{
+       // bot waypoints
+       waypoint_spawnforitem_force(this, this.origin);
+       this.nearestwaypointtimeout = 0; // activate waypointing again
+       this.bot_basewaypoint = this.nearestwaypoint;
+
+       // captureshield setup
+       ons_CaptureShield_Spawn(this, true);
+
+       onslaught_updatelinks();
+
+       Net_LinkEntity(this, false, 0, generator_send);
+}
+
+
+void onslaught_generator_touch(entity this, entity toucher)
+{
+       if ( IS_PLAYER(toucher) )
+       if ( SAME_TEAM(this,toucher) )
+       if ( this.iscaptured )
+       {
+               Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT);
+       }
+}
+
+void ons_GeneratorSetup(entity gen) // called when spawning a generator entity on the map as a spawnfunc
+{
+       // declarations
+       int teamnumber = gen.team;
+
+       // main setup
+       gen.ons_worldgeneratornext = ons_worldgeneratorlist; // link generator into ons_worldgeneratorlist
+       ons_worldgeneratorlist = gen;
+
+       gen.netname = sprintf("%s generator", Team_ColoredFullName(teamnumber));
+       gen.classname = "onslaught_generator";
+       gen.solid = SOLID_BBOX;
+       gen.team_saved = teamnumber;
+       set_movetype(gen, MOVETYPE_NONE);
+       gen.lasthealth = gen.max_health = gen.health = autocvar_g_onslaught_gen_health;
+       gen.takedamage = DAMAGE_AIM;
+       gen.bot_attack = true;
+       IL_PUSH(g_bot_targets, gen);
+       gen.event_damage = ons_GeneratorDamage;
+       gen.reset = ons_GeneratorReset;
+       setthink(gen, ons_GeneratorThink);
+       gen.nextthink = time + GEN_THINKRATE;
+       gen.iscaptured = true;
+       gen.islinked = true;
+       gen.isshielded = true;
+       settouch(gen, onslaught_generator_touch);
+
+       // appearence
+       // model handled by CSQC
+       setsize(gen, GENERATOR_MIN, GENERATOR_MAX);
+       setorigin(gen, (gen.origin + CPGEN_SPAWN_OFFSET));
+       gen.colormap = 1024 + (teamnumber - 1) * 17;
+
+       // generator placement
+       droptofloor(gen);
+
+       // waypointsprites
+       WaypointSprite_SpawnFixed(WP_Null, gen.origin + CPGEN_WAYPOINT_OFFSET, gen, sprite, RADARICON_NONE);
+       WaypointSprite_UpdateRule(gen.sprite, gen.team, SPRITERULE_TEAMPLAY);
+       WaypointSprite_UpdateMaxHealth(gen.sprite, gen.max_health);
+       WaypointSprite_UpdateHealth(gen.sprite, gen.health);
+
+       InitializeEntity(gen, ons_DelayedGeneratorSetup, INITPRIO_SETLOCATION);
+}
+
+
+// ===============
+//  Round Handler
+// ===============
+
+int total_generators;
+void Onslaught_count_generators()
+{
+       entity e;
+       total_generators = redowned = blueowned = yellowowned = pinkowned = 0;
+       for(e = ons_worldgeneratorlist; e; e = e.ons_worldgeneratornext)
+       {
+               ++total_generators;
+               redowned += (e.team == NUM_TEAM_1 && e.health > 0);
+               blueowned += (e.team == NUM_TEAM_2 && e.health > 0);
+               yellowowned += (e.team == NUM_TEAM_3 && e.health > 0);
+               pinkowned += (e.team == NUM_TEAM_4 && e.health > 0);
+       }
+}
+
+int Onslaught_GetWinnerTeam()
+{
+       int winner_team = 0;
+       if(redowned > 0)
+               winner_team = NUM_TEAM_1;
+       if(blueowned > 0)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_2;
+       }
+       if(yellowowned > 0)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_3;
+       }
+       if(pinkowned > 0)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_4;
+       }
+       if(winner_team)
+               return winner_team;
+       return -1; // no generators left?
+}
+
+void nades_Clear(entity e);
+
+#define ONS_OWNED_GENERATORS() ((redowned > 0) + (blueowned > 0) + (yellowowned > 0) + (pinkowned > 0))
+#define ONS_OWNED_GENERATORS_OK() (ONS_OWNED_GENERATORS() > 1)
+bool Onslaught_CheckWinner()
+{
+       if ((autocvar_timelimit && time > game_starttime + autocvar_timelimit * 60) || (round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0))
+       {
+               ons_stalemate = true;
+
+               if (!wpforenemy_announced)
+               {
+                       Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_CONTROLPOINT);
+                       sound(NULL, CH_INFO, SND_ONS_GENERATOR_DECAY, VOL_BASE, ATTEN_NONE);
+
+                       wpforenemy_announced = true;
+               }
+
+               entity tmp_entity; // temporary entity
+               float d;
+               for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext) if(time >= tmp_entity.ons_overtime_damagedelay)
+               {
+                       // tmp_entity.max_health / 300 gives 5 minutes of overtime.
+                       // control points reduce the overtime duration.
+                       d = 1;
+                       entity e;
+                       for(e = ons_worldcplist; e; e = e.ons_worldcpnext)
+                       {
+                               if(DIFF_TEAM(e, tmp_entity))
+                               if(e.islinked)
+                                       d = d + 1;
+                       }
+
+                       if(autocvar_g_campaign && autocvar__campaign_testrun)
+                               d = d * tmp_entity.max_health;
+                       else
+                               d = d * tmp_entity.max_health / max(30, 60 * autocvar_timelimit_suddendeath);
+
+                       Damage(tmp_entity, tmp_entity, tmp_entity, d, DEATH_HURTTRIGGER.m_id, tmp_entity.origin, '0 0 0');
+
+                       tmp_entity.sprite.SendFlags |= 16;
+
+                       tmp_entity.ons_overtime_damagedelay = time + 1;
+               }
+       }
+       else { wpforenemy_announced = false; ons_stalemate = false; }
+
+       Onslaught_count_generators();
+
+       if(ONS_OWNED_GENERATORS_OK())
+               return 0;
+
+       int winner_team = Onslaught_GetWinnerTeam();
+
+       if(winner_team > 0)
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
+               TeamScore_AddToTeam(winner_team, ST_ONS_CAPS, +1);
+       }
+       else if(winner_team == -1)
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_TIED);
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_TIED);
+       }
+
+       ons_stalemate = false;
+
+       play2all(SND(CTF_CAPTURE(winner_team)));
+
+       round_handler_Init(7, autocvar_g_onslaught_warmup, autocvar_g_onslaught_round_timelimit);
+
+       FOREACH_CLIENT(IS_PLAYER(it), {
+               STAT(ROUNDLOST, it) = true;
+               it.player_blocked = true;
+
+               nades_Clear(it);
+       });
+
+       return 1;
+}
+
+bool Onslaught_CheckPlayers()
+{
+       return 1;
+}
+
+void Onslaught_RoundStart()
+{
+       entity tmp_entity;
+       FOREACH_CLIENT(IS_PLAYER(it), it.player_blocked = false);
+
+       for(tmp_entity = ons_worldcplist; tmp_entity; tmp_entity = tmp_entity.ons_worldcpnext)
+               tmp_entity.sprite.SendFlags |= 16;
+
+       for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
+               tmp_entity.sprite.SendFlags |= 16;
+}
+
+
+// ================
+// Bot player logic
+// ================
+
+// NOTE: LEGACY CODE, needs to be re-written!
+
+void havocbot_goalrating_ons_offenseitems(entity this, float ratingscale, vector org, float sradius)
+{
+       bool needarmor = false, needweapons = false;
+
+       // Needs armor/health?
+       if(this.health<100)
+               needarmor = true;
+
+       // Needs weapons?
+       int c = 0;
+       FOREACH(Weapons, it != WEP_Null, {
+               if(this.weapons & (it.m_wepset))
+               if(++c >= 4)
+                       break;
+       });
+
+       if(c<4)
+               needweapons = true;
+
+       if(!needweapons && !needarmor)
+               return;
+
+       LOG_DEBUG(this.netname, " needs weapons ", ftos(needweapons));
+       LOG_DEBUG(this.netname, " needs armor ", ftos(needarmor));
+
+       // See what is around
+       IL_EACH(g_items, it.bot_pickup,
+       {
+               // gather health and armor only
+               if (it.solid)
+               if ( ((it.health || it.armorvalue) && needarmor) || (it.weapons && needweapons ) )
+               if (vdist(it.origin - org, <, sradius))
+               {
+                       int t = it.bot_pickupevalfunc(this, it);
+                       if (t > 0)
+                               navigation_routerating(this, it, t * ratingscale, 500);
+               }
+       });
+}
+
+void havocbot_role_ons_setrole(entity this, int role)
+{
+       LOG_DEBUG(this.netname," switched to ");
+       switch(role)
+       {
+               case HAVOCBOT_ONS_ROLE_DEFENSE:
+                       LOG_DEBUG("defense");
+                       this.havocbot_role = havocbot_role_ons_defense;
+                       this.havocbot_role_flags = HAVOCBOT_ONS_ROLE_DEFENSE;
+                       this.havocbot_role_timeout = 0;
+                       break;
+               case HAVOCBOT_ONS_ROLE_ASSISTANT:
+                       LOG_DEBUG("assistant");
+                       this.havocbot_role = havocbot_role_ons_assistant;
+                       this.havocbot_role_flags = HAVOCBOT_ONS_ROLE_ASSISTANT;
+                       this.havocbot_role_timeout = 0;
+                       break;
+               case HAVOCBOT_ONS_ROLE_OFFENSE:
+                       LOG_DEBUG("offense");
+                       this.havocbot_role = havocbot_role_ons_offense;
+                       this.havocbot_role_flags = HAVOCBOT_ONS_ROLE_OFFENSE;
+                       this.havocbot_role_timeout = 0;
+                       break;
+       }
+       LOG_DEBUG("");
+}
+
+void havocbot_goalrating_ons_controlpoints_attack(entity this, float ratingscale)
+{
+       entity cp, cp1, cp2, best, wp;
+       float radius, bestvalue;
+       int c;
+       bool found;
+
+       // Filter control points
+       for(cp2 = ons_worldcplist; cp2; cp2 = cp2.ons_worldcpnext)
+       {
+               cp2.wpcost = c = 0;
+               cp2.wpconsidered = false;
+
+               if(cp2.isshielded)
+                       continue;
+
+               // Ignore owned controlpoints
+               if(!(cp2.isgenneighbor[this.team] || cp2.iscpneighbor[this.team]))
+                       continue;
+
+               // Count team mates interested in this control point
+               // (easier and cleaner than keeping counters per cp and teams)
+               FOREACH_CLIENT(IS_PLAYER(it), {
+                       if(SAME_TEAM(it, this))
+                       if(it.havocbot_role_flags & HAVOCBOT_ONS_ROLE_OFFENSE)
+                       if(it.havocbot_ons_target == cp2)
+                               ++c;
+               });
+
+               // NOTE: probably decrease the cost of attackable control points
+               cp2.wpcost = c;
+               cp2.wpconsidered = true;
+       }
+
+       // We'll consider only the best case
+       bestvalue = 99999999999;
+       cp = NULL;
+       for(cp1 = ons_worldcplist; cp1; cp1 = cp1.ons_worldcpnext)
+       {
+               if (!cp1.wpconsidered)
+                       continue;
+
+               if(cp1.wpcost<bestvalue)
+               {
+                       bestvalue = cp1.wpcost;
+                       cp = cp1;
+                       this.havocbot_ons_target = cp1;
+               }
+       }
+
+       if (!cp)
+               return;
+
+       LOG_DEBUG(this.netname, " chose cp ranked ", ftos(bestvalue));
+
+       if(cp.goalentity)
+       {
+               // Should be attacked
+               // Rate waypoints near it
+               found = false;
+               best = NULL;
+               bestvalue = 99999999999;
+               for(radius=0; radius<1000 && !found; radius+=500)
+               {
+                       for(wp=findradius(cp.origin,radius); wp; wp=wp.chain)
+                       {
+                               if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
+                               if(wp.classname=="waypoint")
+                               if(checkpvs(wp.origin,cp))
+                               {
+                                       found = true;
+                                       if(wp.cnt<bestvalue)
+                                       {
+                                               best = wp;
+                                               bestvalue = wp.cnt;
+                                       }
+                               }
+                       }
+               }
+
+               if(best)
+               {
+                       navigation_routerating(this, best, ratingscale, 10000);
+                       best.cnt += 1;
+
+                       this.havocbot_attack_time = 0;
+                       if(checkpvs(this.view_ofs,cp))
+                       if(checkpvs(this.view_ofs,best))
+                               this.havocbot_attack_time = time + 2;
+               }
+               else
+               {
+                       navigation_routerating(this, cp, ratingscale, 10000);
+               }
+               LOG_DEBUG(this.netname, " found an attackable controlpoint at ", vtos(cp.origin));
+       }
+       else
+       {
+               // Should be touched
+               LOG_DEBUG(this.netname, " found a touchable controlpoint at ", vtos(cp.origin));
+               found = false;
+
+               // Look for auto generated waypoint
+               if (!bot_waypoints_for_items)
+               for (wp = findradius(cp.origin,100); wp; wp = wp.chain)
+               {
+                       if(wp.classname=="waypoint")
+                       {
+                               navigation_routerating(this, wp, ratingscale, 10000);
+                               found = true;
+                       }
+               }
+
+               // Nothing found, rate the controlpoint itself
+               if (!found)
+                       navigation_routerating(this, cp, ratingscale, 10000);
+       }
+}
+
+bool havocbot_goalrating_ons_generator_attack(entity this, float ratingscale)
+{
+       entity g, wp, bestwp;
+       bool found;
+       int best;
+
+       for(g = ons_worldgeneratorlist; g; g = g.ons_worldgeneratornext)
+       {
+               if(SAME_TEAM(g, this) || g.isshielded)
+                       continue;
+
+               // Should be attacked
+               // Rate waypoints near it
+               found = false;
+               bestwp = NULL;
+               best = 99999999999;
+
+               for(wp=findradius(g.origin,400); wp; wp=wp.chain)
+               {
+                       if(wp.classname=="waypoint")
+                       if(checkpvs(wp.origin,g))
+                       {
+                               found = true;
+                               if(wp.cnt<best)
+                               {
+                                       bestwp = wp;
+                                       best = wp.cnt;
+                               }
+                       }
+               }
+
+               if(bestwp)
+               {
+                       LOG_DEBUG("waypoints found around generator");
+                       navigation_routerating(this, bestwp, ratingscale, 10000);
+                       bestwp.cnt += 1;
+
+                       this.havocbot_attack_time = 0;
+                       if(checkpvs(this.view_ofs,g))
+                       if(checkpvs(this.view_ofs,bestwp))
+                               this.havocbot_attack_time = time + 5;
+
+                       return true;
+               }
+               else
+               {
+                       LOG_DEBUG("generator found without waypoints around");
+                       // if there aren't waypoints near the generator go straight to it
+                       navigation_routerating(this, g, ratingscale, 10000);
+                       this.havocbot_attack_time = 0;
+                       return true;
+               }
+       }
+       return false;
+}
+
+void havocbot_role_ons_offense(entity this)
+{
+       if(IS_DEAD(this))
+       {
+               this.havocbot_attack_time = 0;
+               havocbot_ons_reset_role(this);
+               return;
+       }
+
+       // Set the role timeout if necessary
+       if (!this.havocbot_role_timeout)
+               this.havocbot_role_timeout = time + 120;
+
+       if (time > this.havocbot_role_timeout)
+       {
+               havocbot_ons_reset_role(this);
+               return;
+       }
+
+       if(this.havocbot_attack_time>time)
+               return;
+
+       if (this.bot_strategytime < time)
+       {
+               navigation_goalrating_start(this);
+               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 650);
+               if(!havocbot_goalrating_ons_generator_attack(this, 20000))
+                       havocbot_goalrating_ons_controlpoints_attack(this, 20000);
+               havocbot_goalrating_ons_offenseitems(this, 10000, this.origin, 10000);
+               navigation_goalrating_end(this);
+
+               this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+       }
+}
+
+void havocbot_role_ons_assistant(entity this)
+{
+       havocbot_ons_reset_role(this);
+}
+
+void havocbot_role_ons_defense(entity this)
+{
+       havocbot_ons_reset_role(this);
+}
+
+void havocbot_ons_reset_role(entity this)
+{
+       if(IS_DEAD(this))
+               return;
+
+       this.havocbot_ons_target = NULL;
+
+       // TODO: Defend control points or generator if necessary
+
+       havocbot_role_ons_setrole(this, HAVOCBOT_ONS_ROLE_OFFENSE);
+}
+
+
+/*
+ * Find control point or generator owned by the same team self which is nearest to pos
+ * if max_dist is positive, only control points within this range will be considered
+ */
+entity ons_Nearest_ControlPoint(entity this, vector pos, float max_dist)
+{
+       entity closest_target = NULL;
+       for(entity cp = ons_worldcplist; cp; cp = cp.ons_worldcpnext)
+       {
+               if(SAME_TEAM(cp, this))
+               if(cp.iscaptured)
+               if(max_dist <= 0 || vdist(cp.origin - pos, <=, max_dist))
+               if(vlen2(cp.origin - pos) <= vlen2(closest_target.origin - pos) || closest_target == NULL)
+                       closest_target = cp;
+       }
+       for(entity gen = ons_worldgeneratorlist; gen; gen = gen.ons_worldgeneratornext)
+       {
+               if(SAME_TEAM(gen, this))
+               if(max_dist <= 0 || vdist(gen.origin - pos, <, max_dist))
+               if(vlen2(gen.origin - pos) <= vlen2(closest_target.origin - pos) || closest_target == NULL)
+                       closest_target = gen;
+       }
+
+       return closest_target;
+}
+
+/*
+ * Find control point or generator owned by the same team self which is nearest to pos
+ * if max_dist is positive, only control points within this range will be considered
+ * This function only check distances on the XY plane, disregarding Z
+ */
+entity ons_Nearest_ControlPoint_2D(entity this, vector pos, float max_dist)
+{
+       entity closest_target = NULL;
+       vector delta;
+       float smallest_distance = 0, distance;
+
+       for(entity cp = ons_worldcplist; cp; cp = cp.ons_worldcpnext)
+       {
+               delta = cp.origin - pos;
+               delta_z = 0;
+               distance = vlen(delta);
+
+               if(SAME_TEAM(cp, this))
+               if(cp.iscaptured)
+               if(max_dist <= 0 || distance <= max_dist)
+               if(closest_target == NULL || distance <= smallest_distance )
+               {
+                       closest_target = cp;
+                       smallest_distance = distance;
+               }
+       }
+       for(entity gen = ons_worldgeneratorlist; gen; gen = gen.ons_worldgeneratornext)
+       {
+               delta = gen.origin - pos;
+               delta_z = 0;
+               distance = vlen(delta);
+
+               if(SAME_TEAM(gen, this))
+               if(max_dist <= 0 || distance <= max_dist)
+               if(closest_target == NULL || distance <= smallest_distance )
+               {
+                       closest_target = gen;
+                       smallest_distance = distance;
+               }
+       }
+
+       return closest_target;
+}
+/**
+ * find the number of control points and generators in the same team as this
+ */
+int ons_Count_SelfControlPoints(entity this)
+{
+       int n = 0;
+       for(entity cp = ons_worldcplist; cp; cp = cp.ons_worldcpnext)
+       {
+               if(SAME_TEAM(cp, this))
+               if(cp.iscaptured)
+                       n++;
+       }
+       for(entity gen = ons_worldgeneratorlist; gen; gen = gen.ons_worldgeneratornext)
+       {
+               if(SAME_TEAM(gen, this))
+                       n++;
+       }
+       return n;
+}
+
+/**
+ * Teleport player to a random position near tele_target
+ * if tele_effects is true, teleport sound+particles are created
+ * return false on failure
+ */
+bool ons_Teleport(entity player, entity tele_target, float range, bool tele_effects)
+{
+       if ( !tele_target )
+               return false;
+
+       int i;
+       vector loc;
+       float theta;
+       // narrow the range for each iteration to increase chances that a spawnpoint
+       // can be found even if there's little room around the control point
+       float iteration_scale = 1;
+       for(i = 0; i < 16; ++i)
+       {
+               iteration_scale -= i / 16;
+               theta = random() * 2 * M_PI;
+               loc_y = sin(theta);
+               loc_x = cos(theta);
+               loc_z = 0;
+               loc *= random() * range * iteration_scale;
+
+               loc += tele_target.origin + '0 0 128' * iteration_scale;
+
+               tracebox(loc, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), loc, MOVE_NORMAL, player);
+               if(trace_fraction == 1.0 && !trace_startsolid)
+               {
+                       traceline(tele_target.origin, loc, MOVE_NOMONSTERS, tele_target); // double check to make sure we're not spawning outside the NULL
+                       if(trace_fraction == 1.0 && !trace_startsolid)
+                       {
+                               if ( tele_effects )
+                               {
+                                       Send_Effect(EFFECT_TELEPORT, player.origin, '0 0 0', 1);
+                                       sound (player, CH_TRIGGER, SND_TELEPORT, VOL_BASE, ATTEN_NORM);
+                               }
+                               setorigin(player, loc);
+                               player.angles = '0 1 0' * ( theta * RAD2DEG + 180 );
+                               makevectors(player.angles);
+                               player.fixangle = true;
+                               player.teleport_antispam = time + autocvar_g_onslaught_teleport_wait;
+
+                               if ( tele_effects )
+                                       Send_Effect(EFFECT_TELEPORT, player.origin + v_forward * 32, '0 0 0', 1);
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+// ==============
+// Hook Functions
+// ==============
+
+MUTATOR_HOOKFUNCTION(ons, reset_map_global)
+{
+       FOREACH_CLIENT(IS_PLAYER(it), {
+               STAT(ROUNDLOST, it) = false;
+               it.ons_deathloc = '0 0 0';
+               PutClientInServer(it);
+       });
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, ClientDisconnect)
+{
+       entity player = M_ARGV(0, entity);
+
+       player.ons_deathloc = '0 0 0';
+}
+
+MUTATOR_HOOKFUNCTION(ons, MakePlayerObserver)
+{
+       entity player = M_ARGV(0, entity);
+
+       player.ons_deathloc = '0 0 0';
+}
+
+MUTATOR_HOOKFUNCTION(ons, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(!round_handler_IsRoundStarted())
+       {
+               player.player_blocked = true;
+               return false;
+       }
+
+       entity l;
+       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
+       {
+               l.sprite.SendFlags |= 16;
+       }
+       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
+       {
+               l.sprite.SendFlags |= 16;
+       }
+
+       if(ons_stalemate) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_OVERTIME_CONTROLPOINT); }
+
+       if ( autocvar_g_onslaught_spawn_choose )
+       if ( player.ons_spawn_by )
+       if ( ons_Teleport(player,player.ons_spawn_by,autocvar_g_onslaught_teleport_radius,false) )
+       {
+               player.ons_spawn_by = NULL;
+               return false;
+       }
+
+       if(autocvar_g_onslaught_spawn_at_controlpoints)
+       if(random() <= autocvar_g_onslaught_spawn_at_controlpoints_chance)
+       {
+               float random_target = autocvar_g_onslaught_spawn_at_controlpoints_random;
+               entity tmp_entity, closest_target = NULL;
+               vector spawn_loc = player.ons_deathloc;
+
+               // new joining player or round reset, don't bother checking
+               if(spawn_loc == '0 0 0') { return false; }
+
+               if(random_target) { RandomSelection_Init(); }
+
+               for(tmp_entity = ons_worldcplist; tmp_entity; tmp_entity = tmp_entity.ons_worldcpnext)
+               {
+                       if(SAME_TEAM(tmp_entity, player))
+                       if(random_target)
+                               RandomSelection_Add(tmp_entity, 0, string_null, 1, 1);
+                       else if(vlen2(tmp_entity.origin - spawn_loc) <= vlen2(closest_target.origin - spawn_loc) || closest_target == NULL)
+                               closest_target = tmp_entity;
+               }
+
+               if(random_target) { closest_target = RandomSelection_chosen_ent; }
+
+               if(closest_target)
+               {
+                       float i;
+                       vector loc;
+                       float iteration_scale = 1;
+                       for(i = 0; i < 10; ++i)
+                       {
+                               iteration_scale -= i / 10;
+                               loc = closest_target.origin + '0 0 96' * iteration_scale;
+                               loc += ('0 1 0' * random()) * 128 * iteration_scale;
+                               tracebox(loc, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), loc, MOVE_NORMAL, player);
+                               if(trace_fraction == 1.0 && !trace_startsolid)
+                               {
+                                       traceline(closest_target.origin, loc, MOVE_NOMONSTERS, closest_target); // double check to make sure we're not spawning outside the NULL
+                                       if(trace_fraction == 1.0 && !trace_startsolid)
+                                       {
+                                               setorigin(player, loc);
+                                               player.angles = normalize(loc - closest_target.origin) * RAD2DEG;
+                                               return false;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if(autocvar_g_onslaught_spawn_at_generator)
+       if(random() <= autocvar_g_onslaught_spawn_at_generator_chance)
+       {
+               float random_target = autocvar_g_onslaught_spawn_at_generator_random;
+               entity tmp_entity, closest_target = NULL;
+               vector spawn_loc = player.ons_deathloc;
+
+               // new joining player or round reset, don't bother checking
+               if(spawn_loc == '0 0 0') { return false; }
+
+               if(random_target) { RandomSelection_Init(); }
+
+               for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
+               {
+                       if(random_target)
+                               RandomSelection_Add(tmp_entity, 0, string_null, 1, 1);
+                       else
+                       {
+                               if(SAME_TEAM(tmp_entity, player))
+                               if(vlen2(tmp_entity.origin - spawn_loc) <= vlen2(closest_target.origin - spawn_loc) || closest_target == NULL)
+                                       closest_target = tmp_entity;
+                       }
+               }
+
+               if(random_target) { closest_target = RandomSelection_chosen_ent; }
+
+               if(closest_target)
+               {
+                       float i;
+                       vector loc;
+                       float iteration_scale = 1;
+                       for(i = 0; i < 10; ++i)
+                       {
+                               iteration_scale -= i / 10;
+                               loc = closest_target.origin + '0 0 128' * iteration_scale;
+                               loc += ('0 1 0' * random()) * 256 * iteration_scale;
+                               tracebox(loc, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), loc, MOVE_NORMAL, player);
+                               if(trace_fraction == 1.0 && !trace_startsolid)
+                               {
+                                       traceline(closest_target.origin, loc, MOVE_NOMONSTERS, closest_target); // double check to make sure we're not spawning outside the NULL
+                                       if(trace_fraction == 1.0 && !trace_startsolid)
+                                       {
+                                               setorigin(player, loc);
+                                               player.angles = normalize(loc - closest_target.origin) * RAD2DEG;
+                                               return false;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, PlayerDies)
+{
+       entity frag_target = M_ARGV(2, entity);
+
+       frag_target.ons_deathloc = frag_target.origin;
+       entity l;
+       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
+       {
+               l.sprite.SendFlags |= 16;
+       }
+       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
+       {
+               l.sprite.SendFlags |= 16;
+       }
+
+       if ( autocvar_g_onslaught_spawn_choose )
+       if ( ons_Count_SelfControlPoints(frag_target) > 1 )
+               stuffcmd(frag_target, "qc_cmd_cl hud clickradar\n");
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, MonsterMove)
+{
+       entity mon = M_ARGV(0, entity);
+
+       entity e = find(NULL, targetname, mon.target);
+       if (e != NULL)
+               mon.team = e.team;
+}
+
+void ons_MonsterSpawn_Delayed(entity this)
+{
+       entity own = this.owner;
+
+       if(!own) { delete(this); return; }
+
+       if(own.targetname)
+       {
+               entity e = find(NULL, target, own.targetname);
+               if(e != NULL)
+               {
+                       own.team = e.team;
+
+                       own.use(own, e, NULL);
+               }
+       }
+
+       delete(this);
+}
+
+MUTATOR_HOOKFUNCTION(ons, MonsterSpawn)
+{
+       entity mon = M_ARGV(0, entity);
+
+       entity e = spawn();
+       e.owner = mon;
+       InitializeEntity(e, ons_MonsterSpawn_Delayed, INITPRIO_FINDTARGET);
+}
+
+void ons_TurretSpawn_Delayed(entity this)
+{
+       entity own = this.owner;
+
+       if(!own) { delete(this); return; }
+
+       if(own.targetname)
+       {
+               entity e = find(NULL, target, own.targetname);
+               if(e != NULL)
+               {
+                       own.team = e.team;
+                       own.active = ACTIVE_NOT;
+
+                       own.use(own, e, NULL);
+               }
+       }
+
+       delete(this);
+}
+
+MUTATOR_HOOKFUNCTION(ons, TurretSpawn)
+{
+       entity turret = M_ARGV(0, entity);
+
+       entity e = spawn();
+       e.owner = turret;
+       InitializeEntity(e, ons_TurretSpawn_Delayed, INITPRIO_FINDTARGET);
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, HavocBot_ChooseRole)
+{
+       entity bot = M_ARGV(0, entity);
+
+       havocbot_ons_reset_role(bot);
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ons, GetTeamCount)
+{
+       // onslaught is special
+       for(entity tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
+       {
+               switch(tmp_entity.team)
+               {
+                       case NUM_TEAM_1: c1 = 0; break;
+                       case NUM_TEAM_2: c2 = 0; break;
+                       case NUM_TEAM_3: c3 = 0; break;
+                       case NUM_TEAM_4: c4 = 0; break;
+               }
+       }
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ons, SpectateCopy)
+{
+       entity spectatee = M_ARGV(0, entity);
+       entity client = M_ARGV(1, entity);
+
+       STAT(ROUNDLOST, client) = STAT(ROUNDLOST, spectatee); // make spectators see it too
+}
+
+MUTATOR_HOOKFUNCTION(ons, SV_ParseClientCommand)
+{
+       if(MUTATOR_RETURNVALUE) // command was already handled?
+               return false;
+
+       entity player = M_ARGV(0, entity);
+       string cmd_name = M_ARGV(1, string);
+       int cmd_argc = M_ARGV(2, int);
+
+       if ( cmd_name == "ons_spawn" )
+       {
+               vector pos = player.origin;
+               if(cmd_argc > 1)
+                       pos_x = stof(argv(1));
+               if(cmd_argc > 2)
+                       pos_y = stof(argv(2));
+               if(cmd_argc > 3)
+                       pos_z = stof(argv(3));
+
+               if ( IS_PLAYER(player) )
+               {
+                       if ( !STAT(FROZEN, player) )
+                       {
+                               entity source_point = ons_Nearest_ControlPoint(player, player.origin, autocvar_g_onslaught_teleport_radius);
+
+                               if ( !source_point && player.health > 0 )
+                               {
+                                       sprint(player, "\nYou need to be next to a control point\n");
+                                       return true;
+                               }
+
+
+                               entity closest_target = ons_Nearest_ControlPoint_2D(player, pos, autocvar_g_onslaught_click_radius);
+
+                               if ( closest_target == NULL )
+                               {
+                                       sprint(player, "\nNo control point found\n");
+                                       return true;
+                               }
+
+                               if ( player.health <= 0 )
+                               {
+                                       player.ons_spawn_by = closest_target;
+                                       player.respawn_flags = player.respawn_flags | RESPAWN_FORCE;
+                               }
+                               else
+                               {
+                                       if ( source_point == closest_target )
+                                       {
+                                               sprint(player, "\nTeleporting to the same point\n");
+                                               return true;
+                                       }
+
+                                       if ( !ons_Teleport(player,closest_target,autocvar_g_onslaught_teleport_radius,true) )
+                                               sprint(player, "\nUnable to teleport there\n");
+                               }
+
+                               return true;
+                       }
+
+                       sprint(player, "\nNo teleportation for you\n");
+               }
+
+               return true;
+       }
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, PlayerUseKey)
+{
+       if(MUTATOR_RETURNVALUE || gameover) { return false; }
+
+       entity player = M_ARGV(0, entity);
+
+       if((time > player.teleport_antispam) && (!IS_DEAD(player)) && !player.vehicle)
+       {
+               entity source_point = ons_Nearest_ControlPoint(player, player.origin, autocvar_g_onslaught_teleport_radius);
+               if ( source_point )
+               {
+                       stuffcmd(player, "qc_cmd_cl hud clickradar\n");
+                       return true;
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ons, PlayHitsound)
+{
+       entity frag_victim = M_ARGV(0, entity);
+
+       return (frag_victim.classname == "onslaught_generator" && !frag_victim.isshielded)
+               || (frag_victim.classname == "onslaught_controlpoint_icon" && !frag_victim.owner.isshielded);
+}
+
+MUTATOR_HOOKFUNCTION(ons, SendWaypoint)
+{
+    entity wp = M_ARGV(0, entity);
+    entity to = M_ARGV(1, entity);
+    int sf = M_ARGV(2, int);
+    int wp_flag = M_ARGV(3, int);
+
+       if(sf & 16)
+       {
+               if(wp.owner.classname == "onslaught_controlpoint")
+               {
+                       entity wp_owner = wp.owner;
+                       entity e = WaypointSprite_getviewentity(to);
+                       if(SAME_TEAM(e, wp_owner) && wp_owner.goalentity.health >= wp_owner.goalentity.max_health) { wp_flag |= 2; }
+                       if(!ons_ControlPoint_Attackable(wp_owner, e.team)) { wp_flag |= 2; }
+               }
+               if(wp.owner.classname == "onslaught_generator")
+               {
+                       entity wp_owner = wp.owner;
+                       if(wp_owner.isshielded && wp_owner.health >= wp_owner.max_health) { wp_flag |= 2; }
+                       if(wp_owner.health <= 0) { wp_flag |= 2; }
+               }
+       }
+
+       M_ARGV(3, int) = wp_flag;
+}
+
+MUTATOR_HOOKFUNCTION(ons, TurretValidateTarget)
+{
+       entity turret_target = M_ARGV(1, entity);
+
+       if(substring(turret_target.classname, 0, 10) == "onslaught_") // don't attack onslaught targets, that's the player's job!
+       {
+               M_ARGV(3, float) = -3;
+               return true;
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, TurretThink)
+{
+    entity turret = M_ARGV(0, entity);
+
+       // ONS uses somewhat backwards linking.
+       if(turret.target)
+       {
+               entity e = find(NULL, targetname, turret.target);
+               if (e != NULL)
+                       turret.team = e.team;
+       }
+
+       if(turret.team != turret.tur_head.team)
+               turret_respawn(turret);
+}
+
+
+// ==========
+// Spawnfuncs
+// ==========
+
+/*QUAKED spawnfunc_onslaught_link (0 .5 .8) (-16 -16 -16) (16 16 16)
+  Link between control points.
+
+  This entity targets two different spawnfunc_onslaught_controlpoint or spawnfunc_onslaught_generator entities, and suppresses shielding on both if they are owned by different teams.
+
+keys:
+"target" - first control point.
+"target2" - second control point.
+ */
+spawnfunc(onslaught_link)
+{
+       if(!g_onslaught) { delete(this); return; }
+
+       if (this.target == "" || this.target2 == "")
+               objerror(this, "target and target2 must be set\n");
+
+       this.ons_worldlinknext = ons_worldlinklist; // link into ons_worldlinklist
+       ons_worldlinklist = this;
+
+       InitializeEntity(this, ons_DelayedLinkSetup, INITPRIO_FINDTARGET);
+       Net_LinkEntity(this, false, 0, ons_Link_Send);
+}
+
+/*QUAKED spawnfunc_onslaught_controlpoint (0 .5 .8) (-32 -32 0) (32 32 128)
+  Control point. Be sure to give this enough clearance so that the shootable part has room to exist
+
+  This should link to an spawnfunc_onslaught_controlpoint entity or spawnfunc_onslaught_generator entity.
+
+keys:
+"targetname" - name that spawnfunc_onslaught_link entities will use to target this.
+"target" - target any entities that are tied to this control point, such as vehicles and buildable structure entities.
+"message" - name of this control point (should reflect the location in the map, such as "center bridge", "north tower", etc)
+ */
+
+spawnfunc(onslaught_controlpoint)
+{
+       if(!g_onslaught) { delete(this); return; }
+
+       ons_ControlPoint_Setup(this);
+}
+
+/*QUAKED spawnfunc_onslaught_generator (0 .5 .8) (-32 -32 -24) (32 32 64)
+  Base generator.
+
+  spawnfunc_onslaught_link entities can target this.
+
+keys:
+"team" - team that owns this generator (5 = red, 14 = blue, etc), MUST BE SET.
+"targetname" - name that spawnfunc_onslaught_link entities will use to target this.
+ */
+spawnfunc(onslaught_generator)
+{
+       if(!g_onslaught) { delete(this); return; }
+       if(!this.team) { objerror(this, "team must be set"); }
+
+       ons_GeneratorSetup(this);
+}
+
+// scoreboard setup
+void ons_ScoreRules()
+{
+       CheckAllowedTeams(NULL);
+       int teams = 0;
+       if(c1 >= 0) teams |= BIT(0);
+       if(c2 >= 0) teams |= BIT(1);
+       if(c3 >= 0) teams |= BIT(2);
+       if(c4 >= 0) teams |= BIT(3);
+       ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, true);
+       ScoreInfo_SetLabel_TeamScore  (ST_ONS_CAPS,     "destroyed", SFL_SORT_PRIO_PRIMARY);
+       ScoreInfo_SetLabel_PlayerScore(SP_ONS_CAPS,    "caps",      SFL_SORT_PRIO_SECONDARY);
+       ScoreInfo_SetLabel_PlayerScore(SP_ONS_TAKES,    "takes",     0);
+       ScoreRules_basics_end();
+}
+
+void ons_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up
+{
+       ons_ScoreRules();
+
+       round_handler_Spawn(Onslaught_CheckPlayers, Onslaught_CheckWinner, Onslaught_RoundStart);
+       round_handler_Init(5, autocvar_g_onslaught_warmup, autocvar_g_onslaught_round_timelimit);
+}
+
+void ons_Initialize()
+{
+       g_onslaught = true;
+       ons_captureshield_force = autocvar_g_onslaught_shield_force;
+
+       InitializeEntity(NULL, ons_DelayedInit, INITPRIO_GAMETYPE);
+}
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qh b/qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qh
new file mode 100644 (file)
index 0000000..750ade3
--- /dev/null
@@ -0,0 +1,116 @@
+#pragma once
+
+float autocvar_g_onslaught_point_limit;
+void ons_Initialize();
+
+REGISTER_MUTATOR(ons, false)
+{
+       MUTATOR_ONADD
+       {
+               if (time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+               ons_Initialize();
+
+               ActivateTeamplay();
+               SetLimits(autocvar_g_onslaught_point_limit, autocvar_leadlimit_override, autocvar_timelimit_override, -1);
+               have_team_spawns = -1; // request team spawns
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back ons_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return false;
+}
+
+.entity ons_toucher; // player who touched the control point
+
+// control point / generator constants
+const float ONS_CP_THINKRATE = 0.2;
+const float GEN_THINKRATE = 1;
+#define CPGEN_SPAWN_OFFSET ('0 0 1' * (PL_MAX_CONST.z - 13))
+const vector CPGEN_WAYPOINT_OFFSET = ('0 0 128');
+const vector CPICON_OFFSET = ('0 0 96');
+
+// list of generators on the map
+entity ons_worldgeneratorlist;
+.entity ons_worldgeneratornext;
+
+// list of control points on the map
+entity ons_worldcplist;
+.entity ons_worldcpnext;
+.entity ons_stalecpnext;
+
+// list of links on the map
+entity ons_worldlinklist;
+.entity ons_worldlinknext;
+.entity ons_stalelinknext;
+
+// definitions
+.entity sprite;
+.string target2;
+.int iscaptured;
+.int islinked;
+.int isshielded;
+.float lasthealth;
+.int lastteam;
+.int lastshielded;
+.int lastcaptured;
+
+.bool waslinked;
+
+bool ons_stalemate;
+
+.float teleport_antispam;
+
+// waypoint sprites
+.entity bot_basewaypoint; // generator waypointsprite
+
+.bool isgenneighbor[17];
+.bool iscpneighbor[17];
+float ons_notification_time[17];
+
+.float ons_overtime_damagedelay;
+
+.vector ons_deathloc;
+
+.entity ons_spawn_by;
+
+// declarations for functions used outside gamemode_onslaught.qc
+void ons_Generator_UpdateSprite(entity e);
+void ons_ControlPoint_UpdateSprite(entity e);
+bool ons_ControlPoint_Attackable(entity cp, int teamnumber);
+
+// CaptureShield: Prevent capturing or destroying control point/generator if it is not available yet
+float ons_captureshield_force; // push force of the shield
+
+// bot player logic
+const int HAVOCBOT_ONS_ROLE_NONE               = 0;
+const int HAVOCBOT_ONS_ROLE_DEFENSE    = 2;
+const int HAVOCBOT_ONS_ROLE_ASSISTANT  = 4;
+const int HAVOCBOT_ONS_ROLE_OFFENSE    = 8;
+
+.entity havocbot_ons_target;
+
+.int havocbot_role_flags;
+.float havocbot_attack_time;
+
+void havocbot_role_ons_defense(entity this);
+void havocbot_role_ons_offense(entity this);
+void havocbot_role_ons_assistant(entity this);
+
+void havocbot_ons_reset_role(entity this);
+void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius);
+void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius);
+
+// score rule declarations
+const int ST_ONS_CAPS = 1;
index 3b5dd9550f26286b0ad64b35916fce48dbb1fdc4..6214fac042b7783f96bae24935208873061a9d3f 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
 #include <common/items/all.qc>
+
+#include <common/items/item/_mod.inc>
index 158814c5570bbf929537dbe6bf473e864fc50b50..a04e90b1dce9ef7801f36cccd55094c4efc11ecc 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
 #include <common/items/all.qh>
+
+#include <common/items/item/_mod.qh>
index 7a3e5004696ee1c655a8f5eca7e3cb5cb3506b54..7782cda0d6d1518c47de858484a6123974dcde45 100644 (file)
@@ -1,9 +1,5 @@
-#ifndef ITEMS_ALL_C
-#define ITEMS_ALL_C
 #include "all.qh"
 
-#include "item/_mod.inc"
-
 void Dump_Items()
 {
     FOREACH(Items, true, ITEM_HANDLE(Show, it));
@@ -18,5 +14,3 @@ string Item_Model(string item_mdl)
 #endif
     return output;
 }
-
-#endif
index ff54a3a299f8a3e614fc0e7c62992591b0c8777d..d377776cd554f0bc5c3b0467c755cf8fe641ad37 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <common/command/all.qh>
+#include <common/command/_mod.qh>
 
 #include "item.qh"
 
@@ -29,6 +29,6 @@ GENERIC_COMMAND(dumpitems, "Dump all items to the console") {
     }
 }
 
-#ifndef MENUQC
+#ifdef GAMEQC
 string Item_Model(string item_mdl);
 #endif
index 525a5b3d930a14d07fb47ca546a1dd41b94ef7d0..d7e0dcc6872d0d55b9d7b00aad234920acf5cb45 100644 (file)
@@ -1,84 +1 @@
 #include "ammo.qh"
-#ifdef SVQC
-    #include <common/t_items.qh>
-#endif
-
-#ifndef MENUQC
-MODEL(Bullets_ITEM, Item_Model("a_bullets.mdl"));
-#endif
-
-REGISTER_ITEM(Bullets, Ammo) {
-#ifndef MENUQC
-    this.m_model    =   MDL_Bullets_ITEM;
-#endif
-    this.m_name     =   "bullets";
-    this.m_icon     =   "ammo_bullets";
-#ifdef SVQC
-    this.m_botvalue =   2000;
-    this.m_itemid   =   IT_NAILS;
-#endif
-}
-
-#ifndef MENUQC
-MODEL(Cells_ITEM, Item_Model("a_cells.md3"));
-#endif
-
-REGISTER_ITEM(Cells, Ammo) {
-#ifndef MENUQC
-    this.m_model    =   MDL_Cells_ITEM;
-#endif
-    this.m_name     =   "cells";
-    this.m_icon     =   "ammo_cells";
-#ifdef SVQC
-    this.m_botvalue =   2000;
-    this.m_itemid   =   IT_CELLS;
-#endif
-}
-
-#ifndef MENUQC
-MODEL(Plasma_ITEM, Item_Model("a_cells.md3"));
-#endif
-
-REGISTER_ITEM(Plasma, Ammo) {
-#ifndef MENUQC
-    this.m_model    =   MDL_Plasma_ITEM;
-#endif
-    this.m_name     =   "plasma";
-    this.m_icon     =   "ammo_plasma";
-#ifdef SVQC
-    this.m_botvalue =   2000;
-    this.m_itemid   =   IT_PLASMA;
-#endif
-}
-
-#ifndef MENUQC
-MODEL(Rockets_ITEM, Item_Model("a_rockets.md3"));
-#endif
-
-REGISTER_ITEM(Rockets, Ammo) {
-#ifndef MENUQC
-    this.m_model    =   MDL_Rockets_ITEM;
-#endif
-    this.m_name     =   "rockets";
-    this.m_icon     =   "ammo_rockets";
-#ifdef SVQC
-    this.m_botvalue =   3000;
-    this.m_itemid   =   IT_ROCKETS;
-#endif
-}
-
-#ifndef MENUQC
-MODEL(Shells_ITEM, Item_Model("a_shells.md3"));
-#endif
-
-REGISTER_ITEM(Shells, Ammo) {
-#ifndef MENUQC
-    this.m_model    =   MDL_Shells_ITEM;
-#endif
-    this.m_name     =   "shells";
-    this.m_icon     =   "ammo_shells";
-#ifdef SVQC
-    this.m_botvalue =   500;
-    this.m_itemid   =   IT_SHELLS;
-#endif
-}
index 56c9369192899010fdbabda6d5408028410ae4bd..e1d493fe975a7c50dfcd11af3d9fba717a67c1da 100644 (file)
@@ -8,3 +8,87 @@ CLASS(Ammo, Pickup)
     ATTRIB(Ammo, m_respawntimejitter, float(), GET(g_pickup_respawntimejitter_ammo));
 #endif
 ENDCLASS(Ammo)
+
+#ifdef SVQC
+    #include <common/t_items.qh>
+#endif
+
+#ifdef GAMEQC
+MODEL(Bullets_ITEM, Item_Model("a_bullets.mdl"));
+#endif
+
+REGISTER_ITEM(Bullets, Ammo) {
+#ifdef GAMEQC
+    this.m_model    =   MDL_Bullets_ITEM;
+#endif
+    this.m_name     =   "bullets";
+    this.m_icon     =   "ammo_bullets";
+#ifdef SVQC
+    this.m_botvalue =   2000;
+    this.m_itemid   =   IT_NAILS;
+#endif
+}
+
+#ifdef GAMEQC
+MODEL(Cells_ITEM, Item_Model("a_cells.md3"));
+#endif
+
+REGISTER_ITEM(Cells, Ammo) {
+#ifdef GAMEQC
+    this.m_model    =   MDL_Cells_ITEM;
+#endif
+    this.m_name     =   "cells";
+    this.m_icon     =   "ammo_cells";
+#ifdef SVQC
+    this.m_botvalue =   2000;
+    this.m_itemid   =   IT_CELLS;
+#endif
+}
+
+#ifdef GAMEQC
+MODEL(Plasma_ITEM, Item_Model("a_cells.md3"));
+#endif
+
+REGISTER_ITEM(Plasma, Ammo) {
+#ifdef GAMEQC
+    this.m_model    =   MDL_Plasma_ITEM;
+#endif
+    this.m_name     =   "plasma";
+    this.m_icon     =   "ammo_plasma";
+#ifdef SVQC
+    this.m_botvalue =   2000;
+    this.m_itemid   =   IT_PLASMA;
+#endif
+}
+
+#ifdef GAMEQC
+MODEL(Rockets_ITEM, Item_Model("a_rockets.md3"));
+#endif
+
+REGISTER_ITEM(Rockets, Ammo) {
+#ifdef GAMEQC
+    this.m_model    =   MDL_Rockets_ITEM;
+#endif
+    this.m_name     =   "rockets";
+    this.m_icon     =   "ammo_rockets";
+#ifdef SVQC
+    this.m_botvalue =   3000;
+    this.m_itemid   =   IT_ROCKETS;
+#endif
+}
+
+#ifdef GAMEQC
+MODEL(Shells_ITEM, Item_Model("a_shells.md3"));
+#endif
+
+REGISTER_ITEM(Shells, Ammo) {
+#ifdef GAMEQC
+    this.m_model    =   MDL_Shells_ITEM;
+#endif
+    this.m_name     =   "shells";
+    this.m_icon     =   "ammo_shells";
+#ifdef SVQC
+    this.m_botvalue =   500;
+    this.m_itemid   =   IT_SHELLS;
+#endif
+}
index f8669e0e08503baa95529bef70f2424944ceb159..cca0b541843613470a8d49e0e530283bc2d356de 100644 (file)
@@ -1,89 +1 @@
 #include "armor.qh"
-#ifdef SVQC
-    #include <common/t_items.qh>
-#endif
-
-#ifndef MENUQC
-MODEL(ArmorSmall_ITEM, Item_Model("item_armor_small.md3"));
-SOUND(ArmorSmall, "misc/armor1");
-#endif
-
-REGISTER_ITEM(ArmorSmall, Armor) {
-#ifndef MENUQC
-    this.m_model                =   MDL_ArmorSmall_ITEM;
-    this.m_sound                =   SND_ArmorSmall;
-#endif
-    this.m_name                 =   "5 Armor";
-    this.m_icon                 =   "armor";
-#ifdef SVQC
-    this.m_botvalue             =   BOT_PICKUP_RATING_LOW;
-    this.m_itemid               =   IT_ARMOR_SHARD;
-    this.m_respawntime          =   GET(g_pickup_respawntime_short);
-    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_short);
-#endif
-}
-
-#ifndef MENUQC
-MODEL(ArmorMedium_ITEM, Item_Model("item_armor_medium.md3"));
-SOUND(ArmorMedium, "misc/armor10");
-#endif
-
-REGISTER_ITEM(ArmorMedium, Armor) {
-#ifndef MENUQC
-    this.m_model                =   MDL_ArmorMedium_ITEM;
-    this.m_sound                =   SND_ArmorMedium;
-#endif
-    this.m_name                 =   "25 Armor";
-    this.m_icon                 =   "armor";
-#ifdef SVQC
-    this.m_botvalue             =   BOT_PICKUP_RATING_MID;
-    this.m_itemid               =   IT_ARMOR;
-    this.m_respawntime          =   GET(g_pickup_respawntime_medium);
-    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_medium);
-#endif
-}
-
-#ifndef MENUQC
-MODEL(ArmorLarge_ITEM, Item_Model("item_armor_big.md3"));
-SOUND(ArmorLarge, "misc/armor17_5");
-#endif
-
-REGISTER_ITEM(ArmorLarge, Armor) {
-#ifndef MENUQC
-    this.m_model                =   MDL_ArmorLarge_ITEM;
-    this.m_sound                =   SND_ArmorLarge;
-#endif
-    this.m_name                 =   "50 Armor";
-    this.m_icon                 =   "armor";
-    this.m_color                =   '0 1 0';
-    this.m_waypoint             =   _("Large armor");
-#ifdef SVQC
-    this.m_botvalue             =   20000; // FIXME: higher than BOT_PICKUP_RATING_HIGH?
-    this.m_itemid               =   IT_ARMOR;
-    this.m_respawntime          =   GET(g_pickup_respawntime_long);
-    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_long);
-#endif
-}
-
-#ifndef MENUQC
-MODEL(ArmorMega_ITEM, Item_Model("item_armor_large.md3"));
-SOUND(ArmorMega, "misc/armor25");
-#endif
-
-REGISTER_ITEM(ArmorMega, Armor) {
-#ifndef MENUQC
-    this.m_model                =   MDL_ArmorMega_ITEM;
-    this.m_sound                =   SND_ArmorMega;
-#endif
-    this.m_name                 =   "100 Armor";
-    this.m_icon                 =   "item_large_armor";
-    this.m_color                =   '0 1 0';
-    this.m_waypoint             =   _("Mega armor");
-    this.m_waypointblink        =   2;
-#ifdef SVQC
-    this.m_botvalue             =   BOT_PICKUP_RATING_HIGH;
-    this.m_itemid               =   IT_ARMOR;
-    this.m_respawntime          =   GET(g_pickup_respawntime_long);
-    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_long);
-#endif
-}
index 9078b636d4322b0ac369f8b4dbc2f44f4189baa1..7946fb7b5d3cb651d074492e23687bf799b106a8 100644 (file)
@@ -8,3 +8,92 @@ CLASS(Armor, Pickup)
     ATTRIB(Armor, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc);
 #endif
 ENDCLASS(Armor)
+
+#ifdef SVQC
+    #include <common/t_items.qh>
+#endif
+
+#ifdef GAMEQC
+MODEL(ArmorSmall_ITEM, Item_Model("item_armor_small.md3"));
+SOUND(ArmorSmall, "misc/armor1");
+#endif
+
+REGISTER_ITEM(ArmorSmall, Armor) {
+#ifdef GAMEQC
+    this.m_model                =   MDL_ArmorSmall_ITEM;
+    this.m_sound                =   SND_ArmorSmall;
+#endif
+    this.m_name                 =   "5 Armor";
+    this.m_icon                 =   "armor";
+#ifdef SVQC
+    this.m_botvalue             =   BOT_PICKUP_RATING_LOW;
+    this.m_itemid               =   IT_ARMOR_SHARD;
+    this.m_respawntime          =   GET(g_pickup_respawntime_short);
+    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_short);
+#endif
+}
+
+#ifdef GAMEQC
+MODEL(ArmorMedium_ITEM, Item_Model("item_armor_medium.md3"));
+SOUND(ArmorMedium, "misc/armor10");
+#endif
+
+REGISTER_ITEM(ArmorMedium, Armor) {
+#ifdef GAMEQC
+    this.m_model                =   MDL_ArmorMedium_ITEM;
+    this.m_sound                =   SND_ArmorMedium;
+#endif
+    this.m_name                 =   "25 Armor";
+    this.m_icon                 =   "armor";
+#ifdef SVQC
+    this.m_botvalue             =   BOT_PICKUP_RATING_MID;
+    this.m_itemid               =   IT_ARMOR;
+    this.m_respawntime          =   GET(g_pickup_respawntime_medium);
+    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_medium);
+#endif
+}
+
+#ifdef GAMEQC
+MODEL(ArmorLarge_ITEM, Item_Model("item_armor_big.md3"));
+SOUND(ArmorLarge, "misc/armor17_5");
+#endif
+
+REGISTER_ITEM(ArmorLarge, Armor) {
+#ifdef GAMEQC
+    this.m_model                =   MDL_ArmorLarge_ITEM;
+    this.m_sound                =   SND_ArmorLarge;
+#endif
+    this.m_name                 =   "50 Armor";
+    this.m_icon                 =   "armor";
+    this.m_color                =   '0 1 0';
+    this.m_waypoint             =   _("Large armor");
+#ifdef SVQC
+    this.m_botvalue             =   20000; // FIXME: higher than BOT_PICKUP_RATING_HIGH?
+    this.m_itemid               =   IT_ARMOR;
+    this.m_respawntime          =   GET(g_pickup_respawntime_long);
+    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_long);
+#endif
+}
+
+#ifdef GAMEQC
+MODEL(ArmorMega_ITEM, Item_Model("item_armor_large.md3"));
+SOUND(ArmorMega, "misc/armor25");
+#endif
+
+REGISTER_ITEM(ArmorMega, Armor) {
+#ifdef GAMEQC
+    this.m_model                =   MDL_ArmorMega_ITEM;
+    this.m_sound                =   SND_ArmorMega;
+#endif
+    this.m_name                 =   "100 Armor";
+    this.m_icon                 =   "item_large_armor";
+    this.m_color                =   '0 1 0';
+    this.m_waypoint             =   _("Mega armor");
+    this.m_waypointblink        =   2;
+#ifdef SVQC
+    this.m_botvalue             =   BOT_PICKUP_RATING_HIGH;
+    this.m_itemid               =   IT_ARMOR;
+    this.m_respawntime          =   GET(g_pickup_respawntime_long);
+    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_long);
+#endif
+}
index 93ba2f36e2ab1669bd3b707db541b9a85eac0bd3..49a34c1c8ee280f159139311ae4b245c91a23c4f 100644 (file)
@@ -1,89 +1 @@
 #include "health.qh"
-#ifdef SVQC
-    #include <common/t_items.qh>
-#endif
-
-#ifndef MENUQC
-MODEL(HealthSmall_ITEM, Item_Model("g_h1.md3"));
-SOUND(HealthSmall, "misc/minihealth");
-#endif
-
-REGISTER_ITEM(HealthSmall, Health) {
-#ifndef MENUQC
-    this.m_model                =   MDL_HealthSmall_ITEM;
-    this.m_sound                =   SND_HealthSmall;
-#endif
-    this.m_name                 =   "5 Health";
-    this.m_icon                 =   "health";
-#ifdef SVQC
-    this.m_botvalue             =   BOT_PICKUP_RATING_LOW;
-    this.m_itemid               =   IT_5HP;
-    this.m_respawntime          =   GET(g_pickup_respawntime_short);
-    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_short);
-#endif
-}
-
-#ifndef MENUQC
-MODEL(HealthMedium_ITEM, Item_Model("g_h25.md3"));
-SOUND(HealthMedium, "misc/mediumhealth");
-#endif
-
-REGISTER_ITEM(HealthMedium, Health) {
-#ifndef MENUQC
-    this.m_model                =   MDL_HealthMedium_ITEM;
-    this.m_sound                =   SND_HealthMedium;
-#endif
-    this.m_name                 =   "25 Health";
-    this.m_icon                 =   "health";
-#ifdef SVQC
-    this.m_botvalue             =   BOT_PICKUP_RATING_MID;
-    this.m_itemid               =   IT_25HP;
-    this.m_respawntime          =   GET(g_pickup_respawntime_short);
-    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_short);
-#endif
-}
-
-#ifndef MENUQC
-MODEL(HealthLarge_ITEM, Item_Model("g_h50.md3"));
-SOUND(HealthLarge, "misc/mediumhealth");
-#endif
-
-REGISTER_ITEM(HealthLarge, Health) {
-#ifndef MENUQC
-    this.m_model                =   MDL_HealthLarge_ITEM;
-    this.m_sound                =   SND_HealthLarge;
-#endif
-    this.m_name                 =   "50 Health";
-    this.m_icon                 =   "health";
-    this.m_color                =   '1 0 0';
-    this.m_waypoint             =   _("Large health");
-#ifdef SVQC
-    this.m_botvalue             =   BOT_PICKUP_RATING_MID;
-    this.m_itemid               =   IT_25HP;
-    this.m_respawntime          =   GET(g_pickup_respawntime_medium);
-    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_medium);
-#endif
-}
-
-#ifndef MENUQC
-MODEL(HealthMega_ITEM, Item_Model("g_h100.md3"));
-SOUND(HealthMega, "misc/megahealth");
-#endif
-
-REGISTER_ITEM(HealthMega, Health) {
-#ifndef MENUQC
-    this.m_model                =   MDL_HealthMega_ITEM;
-    this.m_sound                =   SND_HealthMega;
-#endif
-    this.m_name                 =   "100 Health";
-    this.m_icon                 =   "item_mega_health";
-    this.m_color                =   '1 0 0';
-    this.m_waypoint             =   _("Mega health");
-    this.m_waypointblink        =   2;
-#ifdef SVQC
-    this.m_botvalue             =   BOT_PICKUP_RATING_HIGH;
-    this.m_itemid               =   IT_HEALTH;
-    this.m_respawntime          =   GET(g_pickup_respawntime_long);
-    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_long);
-#endif
-}
index 8eb463a8f97ddc9ed66c562748c1fe0732fe8ad3..1597ba605708d944d69b76b10429c0357f0aec91 100644 (file)
@@ -8,3 +8,92 @@ CLASS(Health, Pickup)
     ATTRIB(Health, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc);
 #endif
 ENDCLASS(Health)
+
+#ifdef SVQC
+    #include <common/t_items.qh>
+#endif
+
+#ifdef GAMEQC
+MODEL(HealthSmall_ITEM, Item_Model("g_h1.md3"));
+SOUND(HealthSmall, "misc/minihealth");
+#endif
+
+REGISTER_ITEM(HealthSmall, Health) {
+#ifdef GAMEQC
+    this.m_model                =   MDL_HealthSmall_ITEM;
+    this.m_sound                =   SND_HealthSmall;
+#endif
+    this.m_name                 =   "5 Health";
+    this.m_icon                 =   "health";
+#ifdef SVQC
+    this.m_botvalue             =   BOT_PICKUP_RATING_LOW;
+    this.m_itemid               =   IT_5HP;
+    this.m_respawntime          =   GET(g_pickup_respawntime_short);
+    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_short);
+#endif
+}
+
+#ifdef GAMEQC
+MODEL(HealthMedium_ITEM, Item_Model("g_h25.md3"));
+SOUND(HealthMedium, "misc/mediumhealth");
+#endif
+
+REGISTER_ITEM(HealthMedium, Health) {
+#ifdef GAMEQC
+    this.m_model                =   MDL_HealthMedium_ITEM;
+    this.m_sound                =   SND_HealthMedium;
+#endif
+    this.m_name                 =   "25 Health";
+    this.m_icon                 =   "health";
+#ifdef SVQC
+    this.m_botvalue             =   BOT_PICKUP_RATING_MID;
+    this.m_itemid               =   IT_25HP;
+    this.m_respawntime          =   GET(g_pickup_respawntime_short);
+    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_short);
+#endif
+}
+
+#ifdef GAMEQC
+MODEL(HealthLarge_ITEM, Item_Model("g_h50.md3"));
+SOUND(HealthLarge, "misc/mediumhealth");
+#endif
+
+REGISTER_ITEM(HealthLarge, Health) {
+#ifdef GAMEQC
+    this.m_model                =   MDL_HealthLarge_ITEM;
+    this.m_sound                =   SND_HealthLarge;
+#endif
+    this.m_name                 =   "50 Health";
+    this.m_icon                 =   "health";
+    this.m_color                =   '1 0 0';
+    this.m_waypoint             =   _("Large health");
+#ifdef SVQC
+    this.m_botvalue             =   BOT_PICKUP_RATING_MID;
+    this.m_itemid               =   IT_25HP;
+    this.m_respawntime          =   GET(g_pickup_respawntime_medium);
+    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_medium);
+#endif
+}
+
+#ifdef GAMEQC
+MODEL(HealthMega_ITEM, Item_Model("g_h100.md3"));
+SOUND(HealthMega, "misc/megahealth");
+#endif
+
+REGISTER_ITEM(HealthMega, Health) {
+#ifdef GAMEQC
+    this.m_model                =   MDL_HealthMega_ITEM;
+    this.m_sound                =   SND_HealthMega;
+#endif
+    this.m_name                 =   "100 Health";
+    this.m_icon                 =   "item_mega_health";
+    this.m_color                =   '1 0 0';
+    this.m_waypoint             =   _("Mega health");
+    this.m_waypointblink        =   2;
+#ifdef SVQC
+    this.m_botvalue             =   BOT_PICKUP_RATING_HIGH;
+    this.m_itemid               =   IT_HEALTH;
+    this.m_respawntime          =   GET(g_pickup_respawntime_long);
+    this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_long);
+#endif
+}
index 7fd29e299f57f0034fde2b701fdfe949666f4c34..ec09d5c45d62d904c6e4a2ada5ec570ae3b5c4bc 100644 (file)
@@ -1,66 +1 @@
-#ifdef SVQC
-    #include <common/t_items.qh>
-#endif
-
-#include "ammo.qh"
-#include "powerup.qh"
-
-#ifndef SVQC
-.int m_itemid;
-#endif
-
-#ifndef MENUQC
-MODEL(Jetpack_ITEM, Item_Model("g_jetpack.md3"));
-#endif
-
-REGISTER_ITEM(Jetpack, Powerup) {
-#ifndef MENUQC
-    this.m_model                =   MDL_Jetpack_ITEM;
-    this.m_itemid               =   IT_JETPACK;
-#endif
-    this.m_name                 =   "Jet pack";
-    this.m_icon                 =   "jetpack";
-    this.m_color                =   '0.5 0.5 0.5';
-    this.m_waypoint             =   _("Jet Pack");
-    this.m_waypointblink        =   2;
-#ifdef SVQC
-    this.m_botvalue             =   BOT_PICKUP_RATING_LOW;
-    this.m_pickupevalfunc       =   commodity_pickupevalfunc;
-#endif
-}
-
-#ifndef MENUQC
-MODEL(JetpackFuel_ITEM, Item_Model("g_fuel.md3"));
-#endif
-
-REGISTER_ITEM(JetpackFuel, Ammo) {
-#ifndef MENUQC
-    this.m_model    =   MDL_JetpackFuel_ITEM;
-#endif
-    this.m_name     =   "Fuel";
-    this.m_icon     =   "ammo_fuel";
-#ifdef SVQC
-    this.m_botvalue =   BOT_PICKUP_RATING_LOW;
-    this.m_itemid   =   IT_FUEL;
-#endif
-}
-
-#ifndef MENUQC
-MODEL(JetpackRegen_ITEM, Item_Model("g_fuelregen.md3"));
-#endif
-
-REGISTER_ITEM(JetpackRegen, Powerup) {
-#ifndef MENUQC
-    this.m_model                =   MDL_JetpackRegen_ITEM;
-#endif
-    this.m_name                 =   "Fuel regenerator";
-    this.m_icon                 =   "fuelregen";
-    this.m_color                =   '1 0.5 0';
-    this.m_waypoint             =   _("Fuel regen");
-    this.m_waypointblink        =   2;
-#ifdef SVQC
-    this.m_botvalue             =   BOT_PICKUP_RATING_LOW;
-    this.m_itemid               =   IT_FUEL_REGEN;
-    this.m_pickupevalfunc       =   commodity_pickupevalfunc;
-#endif
-}
+#include "jetpack.qh"
diff --git a/qcsrc/common/items/item/jetpack.qh b/qcsrc/common/items/item/jetpack.qh
new file mode 100644 (file)
index 0000000..8334c79
--- /dev/null
@@ -0,0 +1,68 @@
+#pragma once
+
+#ifdef SVQC
+    #include <common/t_items.qh>
+#endif
+
+#include "ammo.qh"
+#include "powerup.qh"
+
+#ifndef SVQC
+.int m_itemid;
+#endif
+
+#ifdef GAMEQC
+MODEL(Jetpack_ITEM, Item_Model("g_jetpack.md3"));
+#endif
+
+REGISTER_ITEM(Jetpack, Powerup) {
+#ifdef GAMEQC
+    this.m_model                =   MDL_Jetpack_ITEM;
+    this.m_itemid               =   IT_JETPACK;
+#endif
+    this.m_name                 =   "Jet pack";
+    this.m_icon                 =   "jetpack";
+    this.m_color                =   '0.5 0.5 0.5';
+    this.m_waypoint             =   _("Jet Pack");
+    this.m_waypointblink        =   2;
+#ifdef SVQC
+    this.m_botvalue             =   BOT_PICKUP_RATING_LOW;
+    this.m_pickupevalfunc       =   commodity_pickupevalfunc;
+#endif
+}
+
+#ifdef GAMEQC
+MODEL(JetpackFuel_ITEM, Item_Model("g_fuel.md3"));
+#endif
+
+REGISTER_ITEM(JetpackFuel, Ammo) {
+#ifdef GAMEQC
+    this.m_model    =   MDL_JetpackFuel_ITEM;
+#endif
+    this.m_name     =   "Fuel";
+    this.m_icon     =   "ammo_fuel";
+#ifdef SVQC
+    this.m_botvalue =   BOT_PICKUP_RATING_LOW;
+    this.m_itemid   =   IT_FUEL;
+#endif
+}
+
+#ifdef GAMEQC
+MODEL(JetpackRegen_ITEM, Item_Model("g_fuelregen.md3"));
+#endif
+
+REGISTER_ITEM(JetpackRegen, Powerup) {
+#ifdef GAMEQC
+    this.m_model                =   MDL_JetpackRegen_ITEM;
+#endif
+    this.m_name                 =   "Fuel regenerator";
+    this.m_icon                 =   "fuelregen";
+    this.m_color                =   '1 0.5 0';
+    this.m_waypoint             =   _("Fuel regen");
+    this.m_waypointblink        =   2;
+#ifdef SVQC
+    this.m_botvalue             =   BOT_PICKUP_RATING_LOW;
+    this.m_itemid               =   IT_FUEL_REGEN;
+    this.m_pickupevalfunc       =   commodity_pickupevalfunc;
+#endif
+}
index 136c8dab6dbf73c633ab35b548134611e6c9b7a3..204a49921d5f2b84fbc3f30aaff98d692dcbf9e7 100644 (file)
@@ -1,9 +1,33 @@
 #pragma once
 
+#ifdef SVQC
+PROPERTY(float, g_pickup_respawntime_weapon)
+PROPERTY(float, g_pickup_respawntime_superweapon)
+PROPERTY(float, g_pickup_respawntime_ammo)
+PROPERTY(float, g_pickup_respawntime_short)
+PROPERTY(float, g_pickup_respawntime_medium)
+PROPERTY(float, g_pickup_respawntime_long)
+PROPERTY(float, g_pickup_respawntime_powerup)
+PROPERTY(float, g_pickup_respawntimejitter_weapon)
+PROPERTY(float, g_pickup_respawntimejitter_superweapon)
+PROPERTY(float, g_pickup_respawntimejitter_ammo)
+PROPERTY(float, g_pickup_respawntimejitter_short)
+PROPERTY(float, g_pickup_respawntimejitter_medium)
+PROPERTY(float, g_pickup_respawntimejitter_long)
+PROPERTY(float, g_pickup_respawntimejitter_powerup)
+#endif
+
+// pickup ratings for bot logic
+const int BOT_PICKUP_RATING_LOW  =  2500;
+const int BOT_PICKUP_RATING_MID  =  5000;
+const int BOT_PICKUP_RATING_HIGH = 10000;
+
 #include <common/items/inventory.qh>
 #include <common/items/item.qh>
+#include <common/t_items.qh>
+
 CLASS(Pickup, GameItem)
-#ifndef MENUQC
+#ifdef GAMEQC
     ATTRIB(Pickup, m_model, Model);
     ATTRIB(Pickup, m_sound, Sound, SND_ITEMPICKUP);
 #endif
@@ -13,12 +37,12 @@ CLASS(Pickup, GameItem)
         TC(Pickup, this);
         LOG_INFOF("%s: %s\n", etos(this), this.m_name);
     }
+    ATTRIB(Pickup, m_itemid, int, 0);
 #ifdef SVQC
     ATTRIB(Pickup, m_mins, vector, '-16 -16 0');
     ATTRIB(Pickup, m_maxs, vector, '16 16 32');
     ATTRIB(Pickup, m_botvalue, int, 0);
     ATTRIB(Pickup, m_itemflags, int, 0);
-    ATTRIB(Pickup, m_itemid, int, 0);
     float generic_pickupevalfunc(entity player, entity item);
     ATTRIB(Pickup, m_pickupevalfunc, float(entity player, entity item), generic_pickupevalfunc);
     ATTRIB(Pickup, m_respawntime, float());
index 375f958a16ddb798c93ab5de7fdfe48f404dabbd..7c7405b75bb4e34dcad03f2260454c637f19ef48 100644 (file)
@@ -1,37 +1 @@
 #include "powerup.qh"
-
-#ifndef MENUQC
-MODEL(Strength_ITEM, Item_Model("g_strength.md3"));
-SOUND(Strength, "misc/powerup");
-#endif
-
-REGISTER_ITEM(Strength, Powerup) {
-#ifndef MENUQC
-    this.m_model            =   MDL_Strength_ITEM;
-    this.m_sound            =   SND_Strength;
-#endif
-    this.m_name             =   "Strength Powerup";
-    this.m_icon             =   "strength";
-    this.m_color            =   '0 0 1';
-    this.m_waypoint         =   _("Strength");
-    this.m_waypointblink    =   2;
-    this.m_itemid           =   IT_STRENGTH;
-}
-
-#ifndef MENUQC
-MODEL(Shield_ITEM, Item_Model("g_invincible.md3"));
-SOUND(Shield, "misc/powerup_shield");
-#endif
-
-REGISTER_ITEM(Shield, Powerup) {
-#ifndef MENUQC
-    this.m_model            =   MDL_Shield_ITEM;
-    this.m_sound            =   SND_Shield;
-#endif
-    this.m_name             =   "Shield";
-    this.m_icon             =   "shield";
-    this.m_color            =   '1 0 1';
-    this.m_waypoint         =   _("Shield");
-    this.m_waypointblink    =   2;
-    this.m_itemid           =   IT_INVINCIBLE;
-}
index ca17c970bab7aa01066c61e04f0289062314b82e..002be54f805a91dc9b7d56e355a695f60d589b08 100644 (file)
@@ -16,3 +16,39 @@ CLASS(Powerup, Pickup)
     ATTRIB(Powerup, m_respawntimejitter, float(), GET(g_pickup_respawntimejitter_powerup));
 #endif
 ENDCLASS(Powerup)
+
+#ifdef GAMEQC
+MODEL(Strength_ITEM, Item_Model("g_strength.md3"));
+SOUND(Strength, "misc/powerup");
+#endif
+
+REGISTER_ITEM(Strength, Powerup) {
+#ifdef GAMEQC
+    this.m_model            =   MDL_Strength_ITEM;
+    this.m_sound            =   SND_Strength;
+#endif
+    this.m_name             =   "Strength Powerup";
+    this.m_icon             =   "strength";
+    this.m_color            =   '0 0 1';
+    this.m_waypoint         =   _("Strength");
+    this.m_waypointblink    =   2;
+    this.m_itemid           =   IT_STRENGTH;
+}
+
+#ifdef GAMEQC
+MODEL(Shield_ITEM, Item_Model("g_invincible.md3"));
+SOUND(Shield, "misc/powerup_shield");
+#endif
+
+REGISTER_ITEM(Shield, Powerup) {
+#ifdef GAMEQC
+    this.m_model            =   MDL_Shield_ITEM;
+    this.m_sound            =   SND_Shield;
+#endif
+    this.m_name             =   "Shield";
+    this.m_icon             =   "shield";
+    this.m_color            =   '1 0 1';
+    this.m_waypoint         =   _("Shield");
+    this.m_waypointblink    =   2;
+    this.m_itemid           =   IT_INVINCIBLE;
+}
index 2bc84c4593afec5e62a5ddcbbfc689cd2c92d71f..7120c61eda932fa46b9cc2313dc26c8854549293 100644 (file)
@@ -1,13 +1,12 @@
+#include "mapinfo.qh"
 #if defined(CSQC)
     #include "../client/defs.qh"
     #include "util.qh"
-    #include <common/weapons/all.qh>
-    #include "mapinfo.qh"
+    #include <common/weapons/_all.qh>
 #elif defined(MENUQC)
 #elif defined(SVQC)
     #include "util.qh"
-    #include <common/monsters/all.qh>
-    #include "mapinfo.qh"
+    #include <common/monsters/_mod.qh>
 #endif
 
 // generic string stuff
@@ -377,7 +376,7 @@ float _MapInfo_Generate(string pFilename) // 0: failure, 1: ok ent, 2: ok bsp
        }
        if(inWorldspawn)
        {
-               LOG_MAPWARN(fn, " ended still in worldspawn, BUG\n");
+               LOG_WARN(fn, " ended still in worldspawn, BUG");
                return 0;
        }
        diameter = vlen(mapMaxs - mapMins);
@@ -548,7 +547,7 @@ void _MapInfo_Map_ApplyGametypeEx(string s, Gametype pWantedType, Gametype pThis
                if (sa == "") continue;
                int p = strstrofs(sa, "=", 0);
                if (p < 0) {
-                       LOG_MAPWARNF("Invalid gametype setting in mapinfo for gametype %s: %s\n", MapInfo_Type_ToString(pWantedType), sa);
+                       LOG_WARNF("Invalid gametype setting in mapinfo for gametype %s: %s", MapInfo_Type_ToString(pWantedType), sa);
                        continue;
                }
                string k = substring(sa, 0, p);
@@ -588,7 +587,7 @@ void _MapInfo_Map_ApplyGametypeEx(string s, Gametype pWantedType, Gametype pThis
                }
                FOREACH(Gametypes, true, handled |= it.m_parse_mapinfo(k, v));
                if (!handled)
-            LOG_MAPWARNF("Invalid gametype setting in mapinfo for gametype %s: %s\n", MapInfo_Type_ToString(pWantedType), sa);
+            LOG_WARNF("Invalid gametype setting in mapinfo for gametype %s: %s", MapInfo_Type_ToString(pWantedType), sa);
        }
 
        if (pWantedType == MAPINFO_TYPE_RACE && cvar("g_race_teams") >= 2)
@@ -608,7 +607,7 @@ Gametype MapInfo_Type_FromString(string t)
 #define deprecate(from, to) MACRO_BEGIN { \
        if (t == #from) { \
                string replacement = #to; \
-               LOG_MAPWARNF("MapInfo_Type_FromString (probably %s): using deprecated name '%s'. Should use '%s'.\n", MapInfo_Map_bspname, t, replacement); \
+               LOG_WARNF("MapInfo_Type_FromString (probably %s): using deprecated name '%s'. Should use '%s'.", MapInfo_Map_bspname, t, replacement); \
                t = replacement; \
        } \
 } MACRO_END
@@ -678,7 +677,7 @@ void _MapInfo_Parse_Settemp(string pFilename, string acl, float type, string s,
                {
                        fh = fopen(s, FILE_READ);
                        if(fh < 0)
-                               LOG_MAPWARN("Map ", pFilename, " references not existing config file ", s, "\n");
+                               LOG_WARN("Map ", pFilename, " references not existing config file ", s);
                        else
                        {
                                for (;;)
@@ -707,18 +706,18 @@ void _MapInfo_Parse_Settemp(string pFilename, string acl, float type, string s,
                        }
                }
                else
-                       LOG_MAPWARN("Map ", pFilename, " uses too many levels of inclusion\n");
+                       LOG_WARN("Map ", pFilename, " uses too many levels of inclusion");
        }
        else if(t == "")
-               LOG_MAPWARN("Map ", pFilename, " contains a potentially harmful setting, ignored\n");
+               LOG_WARN("Map ", pFilename, " contains a potentially harmful setting, ignored");
        else if (!cvar_value_issafe(t))
-               LOG_MAPWARN("Map ", pFilename, " contains a potentially harmful setting, ignored\n");
+               LOG_WARN("Map ", pFilename, " contains a potentially harmful setting, ignored");
        else if (!cvar_value_issafe(s))
-               LOG_MAPWARN("Map ", pFilename, " contains a potentially harmful setting, ignored\n");
+               LOG_WARN("Map ", pFilename, " contains a potentially harmful setting, ignored");
        else if(matchacl(MAPINFO_SETTEMP_ACL_SYSTEM, t) <= 0)
-               LOG_MAPWARN("Map ", pFilename, " contains a potentially harmful setting, ignored\n");
+               LOG_WARN("Map ", pFilename, " contains a potentially harmful setting, ignored");
        else if(matchacl(acl, t) <= 0)
-               LOG_MAPWARN("Map ", pFilename, " contains a denied setting, ignored\n");
+               LOG_WARN("Map ", pFilename, " contains a denied setting, ignored");
        else
        {
                if(type == 0) // server set
@@ -778,7 +777,7 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
 
        if(strstrofs(pFilename, "/", 0) >= 0)
        {
-               LOG_MAPWARN("Invalid character in map name, ignored\n");
+               LOG_WARN("Invalid character in map name, ignored");
                return 0;
        }
 
@@ -868,7 +867,7 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
                                error("... but I just wrote it!");
                }
 
-               LOG_MAPWARN("autogenerated mapinfo file ", fn, " has been loaded; please edit that file and move it to maps/", pFilename, ".mapinfo\n");
+               LOG_WARN("autogenerated mapinfo file ", fn, " has been loaded; please edit that file and move it to maps/", pFilename, ".mapinfo");
        }
 
        _MapInfo_Map_Reset();
@@ -907,7 +906,7 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
                        else if(t == "monsters") MapInfo_Map_supportedFeatures |= MAPINFO_FEATURE_MONSTERS;
                        else if(t == "new_toys") MapInfo_Map_supportedFeatures |= MAPINFO_FEATURE_WEAPONS;
                        else
-                               LOG_MAPWARN("Map ", pFilename, " supports unknown feature ", t, ", ignored\n");
+                               LOG_WARN("Map ", pFilename, " supports unknown feature ", t, ", ignored");
                }
                else if(t == "hidden")
                {
@@ -934,11 +933,11 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
                {
                        t = car(s); s = cdr(s);
                        Gametype f = MapInfo_Type_FromString(t);
-                       LOG_MAPWARN("Map ", pFilename, " contains the legacy 'type' keyword which is deprecated and will be removed in the future. Please migrate the mapinfo file to 'gametype'.\n");
+                       LOG_WARN("Map ", pFilename, " contains the legacy 'type' keyword which is deprecated and will be removed in the future. Please migrate the mapinfo file to 'gametype'.");
                        if(f)
                                _MapInfo_Map_ApplyGametype (s, pGametypeToSet, f, true);
                        else
-                               LOG_MAPWARN("Map ", pFilename, " supports unknown game type ", t, ", ignored\n");
+                               LOG_WARN("Map ", pFilename, " supports unknown game type ", t, ", ignored");
                }
                else if(t == "gametype")
                {
@@ -947,7 +946,7 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
                        if(f)
                                _MapInfo_Map_ApplyGametypeEx (s, pGametypeToSet, f);
                        else
-                               LOG_MAPWARN("Map ", pFilename, " supports unknown game type ", t, ", ignored\n");
+                               LOG_WARN("Map ", pFilename, " supports unknown game type ", t, ", ignored");
                }
                else if(t == "size")
                {
@@ -958,16 +957,16 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
                        t = car(s); s = cdr(s); d = stof(t);
                        t = car(s); s = cdr(s); e = stof(t);
                        if(s == "")
-                               LOG_MAPWARN("Map ", pFilename, " contains an incorrect size line (not enough params), syntax: size mins_x mins_y mins_z maxs_x maxs_y maxs_z\n");
+                               LOG_WARN("Map ", pFilename, " contains an incorrect size line (not enough params), syntax: size mins_x mins_y mins_z maxs_x maxs_y maxs_z");
                        else
                        {
                                t = car(s); s = cdr(s); f = stof(t);
                                if(s != "")
-                                       LOG_MAPWARN("Map ", pFilename, " contains an incorrect size line (too many params), syntax: size mins_x mins_y mins_z maxs_x maxs_y maxs_z\n");
+                                       LOG_WARN("Map ", pFilename, " contains an incorrect size line (too many params), syntax: size mins_x mins_y mins_z maxs_x maxs_y maxs_z");
                                else
                                {
                                        if(a >= d || b >= e || c >= f)
-                                               LOG_MAPWARN("Map ", pFilename, " contains an incorrect size line, mins have to be < maxs\n");
+                                               LOG_WARN("Map ", pFilename, " contains an incorrect size line, mins have to be < maxs");
                                        else
                                        {
                                                MapInfo_Map_mins.x = a;
@@ -983,39 +982,41 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
                else if(t == "settemp_for_type")
                {
                        t = car(s); s = cdr(s);
-                       Gametype f;
-                       if((f = MapInfo_Type_FromString(t)))
+                       bool all = t == "all";
+                       Gametype f = NULL;
+                       if(all || (f = MapInfo_Type_FromString(t)))
                        {
-                               if(f.m_flags & pGametypeToSet.m_flags)
+                               if((all ? MAPINFO_TYPE_ALL : f.m_flags) & pGametypeToSet.m_flags)
                                {
                                        _MapInfo_Parse_Settemp(pFilename, acl, 0, s, 1);
                                }
                        }
                        else
                        {
-                               LOG_MAPWARN("Map ", pFilename, " has a setting for unknown game type ", t, ", ignored\n");
+                               LOG_WARN("Map ", pFilename, " has a setting for unknown game type ", t, ", ignored");
                        }
                }
                else if(t == "clientsettemp_for_type")
                {
                        t = car(s); s = cdr(s);
-                       Gametype f;
-                       if((f = MapInfo_Type_FromString(t)))
+                       bool all = t == "all";
+                       Gametype f = NULL;
+                       if(all || (f = MapInfo_Type_FromString(t)))
                        {
-                               if(f.m_flags & pGametypeToSet.m_flags)
+                               if((all ? MAPINFO_TYPE_ALL : f.m_flags) & pGametypeToSet.m_flags)
                                {
                                        _MapInfo_Parse_Settemp(pFilename, acl, 1, s, 1);
                                }
                        }
                        else
                        {
-                               LOG_MAPWARN("Map ", pFilename, " has a client setting for unknown game type ", t, ", ignored\n");
+                               LOG_WARN("Map ", pFilename, " has a client setting for unknown game type ", t, ", ignored");
                        }
                }
                else if(t == "fog")
                {
                        if (!cvar_value_issafe(s))
-                               LOG_MAPWARN("Map ", pFilename, " contains a potentially harmful fog setting, ignored\n");
+                               LOG_WARN("Map ", pFilename, " contains a potentially harmful fog setting, ignored");
                        else
                                MapInfo_Map_fog = s;
                }
@@ -1031,7 +1032,7 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
                        if(pGametypeToSet)
                        {
                                if (!cvar_value_issafe(t))
-                                       LOG_MAPWARN("Map ", pFilename, " contains a potentially harmful cdtrack, ignored\n");
+                                       LOG_WARN("Map ", pFilename, " contains a potentially harmful cdtrack, ignored");
                                else
                                        MapInfo_Map_clientstuff = strcat(
                                                MapInfo_Map_clientstuff, "cd loop \"", t, "\"\n"
@@ -1039,7 +1040,7 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
                        }
                }
                else
-                       LOG_MAPWARN("Map ", pFilename, " provides unknown info item ", t, ", ignored\n");
+                       LOG_WARN("Map ", pFilename, " provides unknown info item ", t, ", ignored");
        }
        fclose(fh);
 
@@ -1053,7 +1054,7 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
        MapInfo_Cache_Store();
        if(MapInfo_Map_supportedGametypes != 0)
                return r;
-       LOG_MAPWARN("Map ", pFilename, " supports no game types, ignored\n");
+       LOG_WARN("Map ", pFilename, " supports no game types, ignored");
        return 0;
 }
 int MapInfo_Get_ByName(string pFilename, float pAllowGenerate, Gametype pGametypeToSet)
@@ -1260,10 +1261,11 @@ void MapInfo_LoadMapSettings(string s) // to be called from worldspawn
                        _t <<= 1;
                        MapInfo_Map_supportedGametypes = floor(MapInfo_Map_supportedGametypes >> 1);
                }
+               Gametype t_prev = t;
                FOREACH(Gametypes, it.m_flags == _t, { t = it; break; });
 
                // t is now a supported mode!
-               LOG_WARN("can't play the selected map in the given game mode. Falling back to a supported mode.");
+               LOG_WARNF("can't play the selected map in the given game mode (%s). Falling back to a supported mode (%s).", t_prev.mdl, t.mdl);
                MapInfo_LoadMapSettings_SaveGameType(t);
        }
        MapInfo_Get_ByName(s, 1, t);
@@ -1298,7 +1300,7 @@ int MapInfo_ForbiddenFlags()
 {
        int f = MAPINFO_FLAG_FORBIDDEN;
 
-#ifndef MENUQC
+#ifdef GAMEQC
        if (!cvar("g_maplist_allow_hidden"))
 #endif
                f |= MAPINFO_FLAG_HIDDEN;
index f37e2db060881e23088652e012926e668b731216..a3e000d33351fde6a8f9edb97808375d434670cd 100644 (file)
@@ -1,10 +1,5 @@
 #pragma once
 
-bool autocvar_developer_mapper;
-
-#define LOG_MAPWARN(...) MACRO_BEGIN { if (autocvar_developer_mapper) LOG_WARN(__VA_ARGS__); } MACRO_END
-#define LOG_MAPWARNF(...) MACRO_BEGIN { if (autocvar_developer_mapper) LOG_WARNF(__VA_ARGS__); } MACRO_END
-
 #include "util.qh"
 
 // info about a map that MapInfo loads
@@ -448,7 +443,7 @@ void HUD_Mod_Keepaway(vector pos, vector mySize);
 CLASS(Keepaway, Gametype)
     INIT(Keepaway)
     {
-        this.gametype_init(this, _("Keepaway"),"ka","g_keepaway",true,"","timelimit=20 pointlimit=30",_("Hold the ball to get points for kills"));
+        this.gametype_init(this, _("Keepaway"),"ka","g_keepaway",false,"","timelimit=20 pointlimit=30",_("Hold the ball to get points for kills"));
     }
     METHOD(Keepaway, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
     {
index 43ad69de595d8cace9a34f16d672eeb15baa0815..4171f475cd747c5c7bea37c8e026615dbbea11b1 100644 (file)
@@ -1,5 +1,7 @@
 // generated file; do not modify
-#include <common/minigames/cl_minigames_hud.qc>
+#ifdef CSQC
+    #include <common/minigames/cl_minigames_hud.qc>
+#endif
 #include <common/minigames/minigames.qc>
 #ifdef CSQC
     #include <common/minigames/cl_minigames.qc>
@@ -7,3 +9,5 @@
 #ifdef SVQC
     #include <common/minigames/sv_minigames.qc>
 #endif
+
+#include <common/minigames/minigame/_mod.inc>
index 36f5de2f157fad15c25f288f95a3529363ca686a..e0daf8f6775f01fa6c363b300b55f0c547f07987 100644 (file)
@@ -1,3 +1,13 @@
 // generated file; do not modify
-#include <common/minigames/cl_minigames_hud.qh>
+#ifdef CSQC
+    #include <common/minigames/cl_minigames_hud.qh>
+#endif
 #include <common/minigames/minigames.qh>
+#ifdef CSQC
+    #include <common/minigames/cl_minigames.qh>
+#endif
+#ifdef SVQC
+    #include <common/minigames/sv_minigames.qh>
+#endif
+
+#include <common/minigames/minigame/_mod.qh>
index 90f1b2252ec2c816bea0c566a63725be73424891..a359831dfdd3cb74535c790c34f71b5ba9723721 100644 (file)
@@ -35,7 +35,7 @@ void HUD_MinigameBoard ()
        if ( !hud_minigame )
                return;
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
 
 
        vector pos, mySize;
@@ -61,7 +61,7 @@ void HUD_MinigameStatus ()
        if ( !hud_minigame )
                return;
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
 
 
        vector pos, mySize;
@@ -429,7 +429,7 @@ void HUD_MinigameMenu_MouseInput()
 {
        panel = HUD_PANEL(MINIGAME_MENU);
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
 
        if(panel_bg_padding)
        {
@@ -475,10 +475,10 @@ void HUD_MinigameMenu ()
        if ( !HUD_MinigameMenu_IsOpened() )
                return;
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
 
        HUD_Scale_Disable();
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
 
        if(panel_bg_padding)
        {
@@ -545,7 +545,7 @@ void HUD_MinigameHelp()
        if ( !help_message )
                return;
 
-       HUD_Panel_UpdateCvars();
+       HUD_Panel_LoadCvars();
 
 
        vector pos, mySize;
@@ -682,13 +682,8 @@ void HUD_Minigame_Mouse()
        if( !HUD_MinigameMenu_IsOpened() || autocvar__hud_configure || mv_active )
                return;
 
-       if(!autocvar_hud_cursormode)
-       {
-               mousepos = mousepos + getmousepos() * autocvar_menu_mouse_speed;
-
-               mousepos_x = bound(0, mousepos_x, vid_conwidth);
-               mousepos_y = bound(0, mousepos_y, vid_conheight);
-       }
+       if (!autocvar_hud_cursormode)
+               update_mousepos();
 
        if ( HUD_MinigameMenu_IsOpened() && HUD_mouse_over(HUD_PANEL(MINIGAME_MENU)) )
                HUD_MinigameMenu_MouseInput();
index 041e56339c3039be7f7207c642510a7638202951..31ae9d947912f993571072e8ed89ab551ecfa302 100644 (file)
@@ -1,3 +1,4 @@
+#include "bd.qh"
 REGISTER_MINIGAME(bd, "Bulldozer");
 
 const int BD_TURN_MOVE  = 0x0100; // player must move the bulldozer
@@ -854,7 +855,7 @@ void bd_hud_board(vector pos, vector mySize)
 // Required function, draw the game status panel
 void bd_hud_status(vector pos, vector mySize)
 {
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        vector ts;
        ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
                hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
diff --git a/qcsrc/common/minigames/minigame/bd.qh b/qcsrc/common/minigames/minigame/bd.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 497ef2afc394d24bbe2a46ee0292a94ff0941e11..2a6cb3d475ded6748f10715c5e5e9118e9ce6675 100644 (file)
@@ -1,3 +1,4 @@
+#include "c4.qh"
 REGISTER_MINIGAME(c4, "Connect Four");
 
 const float C4_TURN_PLACE = 0x0100; // player has to place a piece on the board
@@ -322,7 +323,7 @@ void c4_hud_board(vector pos, vector mySize)
 // Required function, draw the game status panel
 void c4_hud_status(vector pos, vector mySize)
 {
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        vector ts;
        ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
                hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
diff --git a/qcsrc/common/minigames/minigame/c4.qh b/qcsrc/common/minigames/minigame/c4.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 78fb30f1df65b4bfc40cf6921d33a25316b97d89..4184c2638251f8df15f3b43a4b594166cba73221 100644 (file)
@@ -1,3 +1,4 @@
+#include "nmm.qh"
 REGISTER_MINIGAME(nmm, "Nine Men's Morris");
 
 const int NMM_TURN_PLACE = 0x0100; // player has to place a piece on the board
@@ -496,9 +497,8 @@ void nmm_hud_board(vector pos, vector mySize)
 // Required function, draw the game status panel
 void nmm_hud_status(vector pos, vector mySize)
 {
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        vector ts;
-
        ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
                hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
        pos_y += ts_y;
diff --git a/qcsrc/common/minigames/minigame/nmm.qh b/qcsrc/common/minigames/minigame/nmm.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index d535b8c85dca031a59c460d118aee7838f001c66..dd57fb5c66886c846458d3991ce1eef96f1707c2 100644 (file)
@@ -1,3 +1,4 @@
+#include "pong.qh"
 REGISTER_MINIGAME(pong, "Pong");
 
 // minigame flags
@@ -542,7 +543,7 @@ void pong_hud_board(vector pos, vector mySize)
 // Required function, draw the game status panel
 void pong_hud_status(vector pos, vector mySize)
 {
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        vector ts;
        ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
                hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
diff --git a/qcsrc/common/minigames/minigame/pong.qh b/qcsrc/common/minigames/minigame/pong.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index f9e0f79b9a92c29459333113448238a826764404..e05658cbf2c0b486f9ccdbeb01e2a53517c2b91b 100644 (file)
@@ -1,3 +1,4 @@
+#include "pp.qh"
 REGISTER_MINIGAME(pp, "Push-Pull");
 
 const int PP_TURN_PLACE = 0x0100; // player has to place a piece on the board
@@ -374,7 +375,7 @@ void pp_hud_board(vector pos, vector mySize)
 // Required function, draw the game status panel
 void pp_hud_status(vector pos, vector mySize)
 {
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        vector ts;
        ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
                hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
diff --git a/qcsrc/common/minigames/minigame/pp.qh b/qcsrc/common/minigames/minigame/pp.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index c9ef8bd67a4ae9fad1bed23776646f2485b1bad1..cd5c001e7adf95a30802b03bf468f857692bc9df 100644 (file)
@@ -1,3 +1,4 @@
+#include "ps.qh"
 REGISTER_MINIGAME(ps, "Peg Solitaire");
 
 const float PS_TURN_MOVE  = 0x0100; // player has to click on a piece on the board
@@ -429,7 +430,7 @@ void ps_hud_board(vector pos, vector mySize)
 // Required function, draw the game status panel
 void ps_hud_status(vector pos, vector mySize)
 {
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        vector ts;
        ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
                hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
diff --git a/qcsrc/common/minigames/minigame/ps.qh b/qcsrc/common/minigames/minigame/ps.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 4248d589a13391c0f6218d518a155f0cf5727556..cd45ed96d6662cada5cdf4d9f669ded4a4e1e61d 100644 (file)
@@ -1,3 +1,4 @@
+#include "snake.qh"
 REGISTER_MINIGAME(snake, "Snake"); // SNAAAAKE
 
 const float SNAKE_TURN_MOVE  = 0x0100; // the snake is moving, player must control it
@@ -673,7 +674,7 @@ void snake_hud_board(vector pos, vector mySize)
 // Required function, draw the game status panel
 void snake_hud_status(vector pos, vector mySize)
 {
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        vector ts;
        ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
                hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
diff --git a/qcsrc/common/minigames/minigame/snake.qh b/qcsrc/common/minigames/minigame/snake.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 9c0ece163343e840075cb463f79086113ba90e49..e06bb46628c5366db60f07a129feaf0cc18358f7 100644 (file)
@@ -1,3 +1,4 @@
+#include "ttt.qh"
 REGISTER_MINIGAME(ttt, "Tic Tac Toe");
 
 const int TTT_TURN_PLACE = 0x0100; // player has to place a piece on the board
@@ -272,7 +273,7 @@ void ttt_hud_board(vector pos, vector mySize)
 // Required function, draw the game status panel
 void ttt_hud_status(vector pos, vector mySize)
 {
-       HUD_Panel_DrawBg(1);
+       HUD_Panel_DrawBg();
        vector ts;
        ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
                hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
diff --git a/qcsrc/common/minigames/minigame/ttt.qh b/qcsrc/common/minigames/minigame/ttt.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index da04340a63c3bcbc21c8ed6d7f7a9f60aa6565eb..5f1d1280b9f5a35dd85e2e4d99b6127767ee93c2 100644 (file)
@@ -1,3 +1,4 @@
+#include "sv_minigames.qh"
 #include "minigames.qh"
 
 void player_clear_minigame(entity player)
index f9d80b3f4e36f6de4e97cc4e84fe442b559e8e5b..be50e5503f70f2d660263fd15f68c98aa991bd40 100644 (file)
@@ -1,4 +1,10 @@
 // generated file; do not modify
 #include <common/monsters/all.qc>
-#include <common/monsters/spawn.qc>
-#include <common/monsters/sv_monsters.qc>
+#ifdef SVQC
+    #include <common/monsters/sv_monsters.qc>
+#endif
+#ifdef SVQC
+    #include <common/monsters/sv_spawn.qc>
+#endif
+
+#include <common/monsters/monster/_mod.inc>
index 48427f94f7dbd2c779f5e939a90d2b3ccb122b90..55204bd1a770ec46b66e48222b6d0ae3fcbf62e7 100644 (file)
@@ -1,4 +1,10 @@
 // generated file; do not modify
 #include <common/monsters/all.qh>
-#include <common/monsters/spawn.qh>
-#include <common/monsters/sv_monsters.qh>
+#ifdef SVQC
+    #include <common/monsters/sv_monsters.qh>
+#endif
+#ifdef SVQC
+    #include <common/monsters/sv_spawn.qh>
+#endif
+
+#include <common/monsters/monster/_mod.qh>
index fa3f65193ae5725bc0e4a87806433875344a23f3..9dc09ca394b47166bc4d717901d0aa17f6465664 100644 (file)
@@ -1,5 +1,4 @@
-#ifndef MONSTERS_ALL_C
-#define MONSTERS_ALL_C
+#include "all.qh"
 
 string M_Model(string m_mdl)
 {
@@ -11,16 +10,3 @@ string M_Model(string m_mdl)
        return output;
 #endif
 }
-
-#include "all.qh"
-
-#define IMPLEMENTATION
-#include "monster/_mod.inc"
-#undef IMPLEMENTATION
-
-#ifdef SVQC
-#include "spawn.qc"
-#include "sv_monsters.qc"
-#endif
-
-#endif
index 84f7a0d78f6d19d4121334681655c170e19f2569..c9e5ad37ba6448ed85374378affde2e871a6197c 100644 (file)
@@ -1,7 +1,5 @@
 #pragma once
 
-#include "monster.qh"
-
 string M_Model(string m_mdl);
 
 REGISTRY(Monsters, BITS(5))
@@ -13,7 +11,6 @@ const int MON_FIRST = 1;
 #define MON_LAST (Monsters_COUNT - 1)
 #define REGISTER_MONSTER(id, inst) REGISTER(Monsters, MON, id, monsterid, inst)
 
-REGISTER_MONSTER(Null, NEW(Monster));
-
+#include "monster.qh"
 
-#include "monster/_mod.inc"
+REGISTER_MONSTER(Null, NEW(Monster));
index 5187c7f56b17f576771778ff3f2a7b0652b0bde2..babf6e4faf19a2f1e1879afd774693a05514c762 100644 (file)
@@ -1,22 +1,5 @@
 #pragma once
 
-#ifdef SVQC
-#include "sv_monsters.qh"
-#include <server/g_damage.qh>
-#include <server/bot/api.qh>
-#include <server/weapons/common.qh>
-#include <server/weapons/tracing.qh>
-#include <server/weapons/weaponsystem.qh>
-#include <common/mutators/mutator/waypoints/waypointsprites.qh>
-#include <lib/warpzone/server.qh>
-#endif
-
-#ifndef MENUQC
-#include "../animdecide.qh"
-#include "../anim.qh"
-vector animfixfps(entity e, vector a, vector b);
-#endif
-
 // special spawn flags
 const int MONSTER_RESPAWN_DEATHPOINT = 16; // re-spawn where we died
 const int MONSTER_TYPE_FLY = 32;
@@ -73,3 +56,21 @@ CLASS(Monster, Object)
     METHOD(Monster, mr_anim, bool(Monster this, entity actor)) { TC(Monster, this); return false; }
 
 ENDCLASS(Monster)
+
+
+#ifdef SVQC
+#include "sv_monsters.qh"
+#include <server/g_damage.qh>
+#include <server/bot/api.qh>
+#include <server/weapons/common.qh>
+#include <server/weapons/tracing.qh>
+#include <server/weapons/weaponsystem.qh>
+#include <common/mutators/mutator/waypoints/waypointsprites.qh>
+#include <lib/warpzone/server.qh>
+#endif
+
+#ifdef GAMEQC
+#include "../animdecide.qh"
+#include "../anim.qh"
+vector animfixfps(entity e, vector a, vector b);
+#endif
index 509fa0aca11bc6cfdc277af9c14f545d081e13ce..30d09807f2f9faf9c4462c30b07c36bb117983e9 100644 (file)
@@ -1,41 +1,4 @@
-#ifndef MAGE_H
-#define MAGE_H
-
-#ifndef MENUQC
-MODEL(MON_MAGE, M_Model("mage.dpm"));
-#endif
-
-CLASS(Mage, Monster)
-    ATTRIB(Mage, spawnflags, int, MON_FLAG_MELEE | MON_FLAG_RANGED);
-    ATTRIB(Mage, mins, vector, '-36 -36 -24');
-    ATTRIB(Mage, maxs, vector, '36 36 50');
-#ifndef MENUQC
-    ATTRIB(Mage, m_model, Model, MDL_MON_MAGE);
-#endif
-    ATTRIB(Mage, netname, string, "mage");
-    ATTRIB(Mage, monster_name, string, _("Mage"));
-ENDCLASS(Mage)
-
-REGISTER_MONSTER(MAGE, NEW(Mage)) {
-#ifndef MENUQC
-    this.mr_precache(this);
-#endif
-}
-
-#include <common/weapons/all.qh>
-#include <common/items/all.qc>
-
-CLASS(MageSpike, PortoLaunch)
-/* flags     */ ATTRIB(MageSpike, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
-/* impulse   */ ATTRIB(MageSpike, impulse, int, 9);
-/* refname   */ ATTRIB(MageSpike, netname, string, "magespike");
-/* wepname   */ ATTRIB(MageSpike, m_name, string, _("Mage spike"));
-ENDCLASS(MageSpike)
-REGISTER_WEAPON(MAGE_SPIKE, NEW(MageSpike));
-
-#endif
-
-#ifdef IMPLEMENTATION
+#include "mage.qh"
 
 #ifdef SVQC
 
@@ -236,6 +199,7 @@ void M_Mage_Attack_Spike(entity this, vector dir)
        set_movetype(missile, MOVETYPE_FLYMISSILE);
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
+       IL_PUSH(g_bot_dodge, missile);
        setorigin(missile, this.origin + v_forward * 14 + '0 0 30' + v_right * -14);
        setsize(missile, '0 0 0', '0 0 0');
        missile.velocity = dir * 400;
@@ -417,10 +381,9 @@ METHOD(Mage, mr_think, bool(Mage thismon, entity actor))
     TC(Mage, thismon);
     bool need_help = false;
 
-    FOREACH_ENTITY_FLOAT(iscreature, true,
+    FOREACH_CLIENT(IS_PLAYER(it) && it != actor,
     {
-        if(it != actor)
-        if(vdist(it.origin - actor.origin, <=, autocvar_g_monster_mage_heal_range))
+       if(vdist(it.origin - actor.origin, <=, autocvar_g_monster_mage_heal_range))
         if(M_Mage_Defend_Heal_Check(actor, it))
         {
             need_help = true;
@@ -428,6 +391,19 @@ METHOD(Mage, mr_think, bool(Mage thismon, entity actor))
         }
     });
 
+    if(!need_help)
+    {
+       IL_EACH(g_monsters, it != actor,
+       {
+               if(vdist(it.origin - actor.origin, <=, autocvar_g_monster_mage_heal_range))
+               if(M_Mage_Defend_Heal_Check(actor, it))
+               {
+                   need_help = true;
+                   break;
+               }
+       });
+    }
+
     if(actor.health < (autocvar_g_monster_mage_heal_minhealth) || need_help)
     if(time >= actor.attack_finished_single[0])
     if(random() < 0.5)
@@ -459,7 +435,7 @@ METHOD(Mage, mr_death, bool(Mage this, entity actor))
 }
 
 #endif
-#ifndef MENUQC
+#ifdef GAMEQC
 METHOD(Mage, mr_anim, bool(Mage this, entity actor))
 {
     TC(Mage, this);
@@ -497,5 +473,3 @@ METHOD(Mage, mr_precache, bool(Mage this))
     return true;
 }
 #endif
-
-#endif
diff --git a/qcsrc/common/monsters/monster/mage.qh b/qcsrc/common/monsters/monster/mage.qh
new file mode 100644 (file)
index 0000000..d78ee5e
--- /dev/null
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "../all.qh"
+
+#ifdef GAMEQC
+MODEL(MON_MAGE, M_Model("mage.dpm"));
+#endif
+
+CLASS(Mage, Monster)
+    ATTRIB(Mage, spawnflags, int, MON_FLAG_MELEE | MON_FLAG_RANGED);
+    ATTRIB(Mage, mins, vector, '-36 -36 -24');
+    ATTRIB(Mage, maxs, vector, '36 36 50');
+#ifdef GAMEQC
+    ATTRIB(Mage, m_model, Model, MDL_MON_MAGE);
+#endif
+    ATTRIB(Mage, netname, string, "mage");
+    ATTRIB(Mage, monster_name, string, _("Mage"));
+ENDCLASS(Mage)
+
+REGISTER_MONSTER(MAGE, NEW(Mage)) {
+#ifdef GAMEQC
+    this.mr_precache(this);
+#endif
+}
+
+#include <common/weapons/_all.qh>
+#include <common/items/_mod.qh>
+
+CLASS(MageSpike, PortoLaunch)
+/* flags     */ ATTRIB(MageSpike, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* impulse   */ ATTRIB(MageSpike, impulse, int, 9);
+/* refname   */ ATTRIB(MageSpike, netname, string, "magespike");
+/* wepname   */ ATTRIB(MageSpike, m_name, string, _("Mage spike"));
+ENDCLASS(MageSpike)
+REGISTER_WEAPON(MAGE_SPIKE, NEW(MageSpike));
index eb615fb55483d7e5665fe7f698d8472acbb206dd..8f84bdce31d70778f2989c696a14198f7aa29ac5 100644 (file)
@@ -1,30 +1,4 @@
-#ifndef SHAMBLER_H
-#define SHAMBLER_H
-
-#ifndef MENUQC
-MODEL(MON_SHAMBLER, M_Model("shambler.mdl"));
-#endif
-
-CLASS(Shambler, Monster)
-    ATTRIB(Shambler, spawnflags, int, MONSTER_SIZE_BROKEN | MON_FLAG_SUPERMONSTER | MON_FLAG_MELEE | MON_FLAG_RANGED);
-    ATTRIB(Shambler, mins, vector, '-41 -41 -31');
-    ATTRIB(Shambler, maxs, vector, '41 41 65');
-#ifndef MENUQC
-    ATTRIB(Shambler, m_model, Model, MDL_MON_SHAMBLER);
-#endif
-    ATTRIB(Shambler, netname, string, "shambler");
-    ATTRIB(Shambler, monster_name, string, _("Shambler"));
-ENDCLASS(Shambler)
-
-REGISTER_MONSTER(SHAMBLER, NEW(Shambler)) {
-#ifndef MENUQC
-    this.mr_precache(this);
-#endif
-}
-
-#endif
-
-#ifdef IMPLEMENTATION
+#include "shambler.qh"
 
 #ifdef SVQC
 float autocvar_g_monster_shambler_health;
@@ -174,6 +148,7 @@ void M_Shambler_Attack_Lightning(entity this)
        gren.angles = vectoangles (gren.velocity);
        gren.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, gren);
+       IL_PUSH(g_bot_dodge, gren);
 
        CSQCProjectile(gren, true, PROJECTILE_SHAMBLER_LIGHTNING, true);
 }
@@ -250,7 +225,7 @@ METHOD(Shambler, mr_death, bool(Shambler this, entity actor))
     return true;
 }
 #endif
-#ifndef MENUQC
+#ifdef GAMEQC
 METHOD(Shambler, mr_anim, bool(Shambler this, entity actor))
 {
     TC(Shambler, this);
@@ -297,5 +272,3 @@ METHOD(Shambler, mr_precache, bool(Shambler this))
     return true;
 }
 #endif
-
-#endif
diff --git a/qcsrc/common/monsters/monster/shambler.qh b/qcsrc/common/monsters/monster/shambler.qh
new file mode 100644 (file)
index 0000000..f7a3ce3
--- /dev/null
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "../all.qh"
+
+#ifdef GAMEQC
+MODEL(MON_SHAMBLER, M_Model("shambler.mdl"));
+#endif
+
+CLASS(Shambler, Monster)
+    ATTRIB(Shambler, spawnflags, int, MONSTER_SIZE_BROKEN | MON_FLAG_SUPERMONSTER | MON_FLAG_MELEE | MON_FLAG_RANGED);
+    ATTRIB(Shambler, mins, vector, '-41 -41 -31');
+    ATTRIB(Shambler, maxs, vector, '41 41 65');
+#ifdef GAMEQC
+    ATTRIB(Shambler, m_model, Model, MDL_MON_SHAMBLER);
+#endif
+    ATTRIB(Shambler, netname, string, "shambler");
+    ATTRIB(Shambler, monster_name, string, _("Shambler"));
+ENDCLASS(Shambler)
+
+REGISTER_MONSTER(SHAMBLER, NEW(Shambler)) {
+#ifdef GAMEQC
+    this.mr_precache(this);
+#endif
+}
index 9fa73508c1bcb4327d2ad7067a7e066cc5b365b9..d2cb8313e3f022402353736f94ac839da415114b 100644 (file)
@@ -1,40 +1,4 @@
-#ifndef SPIDER_H
-#define SPIDER_H
-
-#ifndef MENUQC
-MODEL(MON_SPIDER, M_Model("spider.dpm"));
-#endif
-
-CLASS(Spider, Monster)
-    ATTRIB(Spider, spawnflags, int, MON_FLAG_MELEE | MON_FLAG_RANGED | MON_FLAG_RIDE);
-    ATTRIB(Spider, mins, vector, '-18 -18 -25');
-    ATTRIB(Spider, maxs, vector, '18 18 30');
-#ifndef MENUQC
-    ATTRIB(Spider, m_model, Model, MDL_MON_SPIDER);
-#endif
-    ATTRIB(Spider, netname, string, "spider");
-    ATTRIB(Spider, monster_name, string, _("Spider"));
-ENDCLASS(Spider)
-
-REGISTER_MONSTER(SPIDER, NEW(Spider)) {
-#ifndef MENUQC
-    this.mr_precache(this);
-#endif
-}
-
-#include <common/weapons/all.qh>
-
-CLASS(SpiderAttack, PortoLaunch)
-/* flags     */ ATTRIB(SpiderAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
-/* impulse   */ ATTRIB(SpiderAttack, impulse, int, 9);
-/* refname   */ ATTRIB(SpiderAttack, netname, string, "spider");
-/* wepname   */ ATTRIB(SpiderAttack, m_name, string, _("Spider attack"));
-ENDCLASS(SpiderAttack)
-REGISTER_WEAPON(SPIDER_ATTACK, NEW(SpiderAttack));
-
-#endif
-
-#ifdef IMPLEMENTATION
+#include "spider.qh"
 
 #ifdef SVQC
 
@@ -195,6 +159,7 @@ void M_Spider_Attack_Web(entity this)
        proj.event_damage = func_null;
        proj.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, proj);
+       IL_PUSH(g_bot_dodge, proj);
        proj.damagedbycontents = true;
 
        proj.bouncefactor = 0.3;
@@ -249,7 +214,7 @@ METHOD(Spider, mr_death, bool(Spider this, entity actor))
     return true;
 }
 #endif
-#ifndef MENUQC
+#ifdef GAMEQC
 METHOD(Spider, mr_anim, bool(Spider this, entity actor))
 {
     TC(Spider, this);
@@ -285,5 +250,3 @@ METHOD(Spider, mr_precache, bool(Spider this))
     return true;
 }
 #endif
-
-#endif
diff --git a/qcsrc/common/monsters/monster/spider.qh b/qcsrc/common/monsters/monster/spider.qh
new file mode 100644 (file)
index 0000000..c54eb3a
--- /dev/null
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "../all.qh"
+
+#ifdef GAMEQC
+MODEL(MON_SPIDER, M_Model("spider.dpm"));
+#endif
+
+CLASS(Spider, Monster)
+    ATTRIB(Spider, spawnflags, int, MON_FLAG_MELEE | MON_FLAG_RANGED | MON_FLAG_RIDE);
+    ATTRIB(Spider, mins, vector, '-18 -18 -25');
+    ATTRIB(Spider, maxs, vector, '18 18 30');
+#ifdef GAMEQC
+    ATTRIB(Spider, m_model, Model, MDL_MON_SPIDER);
+#endif
+    ATTRIB(Spider, netname, string, "spider");
+    ATTRIB(Spider, monster_name, string, _("Spider"));
+ENDCLASS(Spider)
+
+REGISTER_MONSTER(SPIDER, NEW(Spider)) {
+#ifdef GAMEQC
+    this.mr_precache(this);
+#endif
+}
+
+#include <common/weapons/_all.qh>
+
+CLASS(SpiderAttack, PortoLaunch)
+/* flags     */ ATTRIB(SpiderAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* impulse   */ ATTRIB(SpiderAttack, impulse, int, 9);
+/* refname   */ ATTRIB(SpiderAttack, netname, string, "spider");
+/* wepname   */ ATTRIB(SpiderAttack, m_name, string, _("Spider attack"));
+ENDCLASS(SpiderAttack)
+REGISTER_WEAPON(SPIDER_ATTACK, NEW(SpiderAttack));
index 33a3c445991c274ed87a520d4d326afb4850eabe..3fd7ec967679e05b750349427f0b2b68d6bf1a32 100644 (file)
@@ -1,40 +1,4 @@
-#ifndef WYVERN_H
-#define WYVERN_H
-
-#ifndef MENUQC
-MODEL(MON_WYVERN, M_Model("wizard.mdl"));
-#endif
-
-CLASS(Wyvern, Monster)
-    ATTRIB(Wyvern, spawnflags, int, MONSTER_TYPE_FLY | MONSTER_SIZE_BROKEN | MON_FLAG_RANGED | MON_FLAG_RIDE);
-    ATTRIB(Wyvern, mins, vector, '-20 -20 -58');
-    ATTRIB(Wyvern, maxs, vector, '20 20 20');
-#ifndef MENUQC
-    ATTRIB(Wyvern, m_model, Model, MDL_MON_WYVERN);
-#endif
-    ATTRIB(Wyvern, netname, string, "wyvern");
-    ATTRIB(Wyvern, monster_name, string, _("Wyvern"));
-ENDCLASS(Wyvern)
-
-REGISTER_MONSTER(WYVERN, NEW(Wyvern)) {
-#ifndef MENUQC
-    this.mr_precache(this);
-#endif
-}
-
-#include <common/weapons/all.qh>
-
-CLASS(WyvernAttack, PortoLaunch)
-/* flags     */ ATTRIB(WyvernAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
-/* impulse   */ ATTRIB(WyvernAttack, impulse, int, 9);
-/* refname   */ ATTRIB(WyvernAttack, netname, string, "wyvern");
-/* wepname   */ ATTRIB(WyvernAttack, m_name, string, _("Wyvern attack"));
-ENDCLASS(WyvernAttack)
-REGISTER_WEAPON(WYVERN_ATTACK, NEW(WyvernAttack));
-
-#endif
-
-#ifdef IMPLEMENTATION
+#include "wyvern.qh"
 
 #ifdef SVQC
 
@@ -70,6 +34,7 @@ METHOD(WyvernAttack, wr_think, void(WyvernAttack thiswep, entity actor, .entity
                setorigin(missile, actor.origin + actor.view_ofs + v_forward * 14);
                missile.flags = FL_PROJECTILE;
         IL_PUSH(g_projectiles, missile);
+        IL_PUSH(g_bot_dodge, missile);
                missile.velocity = w_shotdir * (autocvar_g_monster_wyvern_attack_fireball_speed);
                missile.avelocity = '300 300 300';
                missile.nextthink = time + 5;
@@ -108,10 +73,9 @@ void M_Wyvern_Attack_Fireball_Explode(entity this)
 
        RadiusDamage(this, own, autocvar_g_monster_wyvern_attack_fireball_damage, autocvar_g_monster_wyvern_attack_fireball_edgedamage, autocvar_g_monster_wyvern_attack_fireball_force, NULL, NULL, autocvar_g_monster_wyvern_attack_fireball_radius, this.projectiledeathtype, NULL);
 
-       FOREACH_ENTITY_FLOAT(takedamage, DAMAGE_AIM,
+       FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_wyvern_attack_fireball_radius, it.takedamage == DAMAGE_AIM,
        {
-               if(vdist(it.origin - this.origin, <=, autocvar_g_monster_wyvern_attack_fireball_radius))
-                       Fire_AddDamage(it, own, 5 * MONSTER_SKILLMOD(own), autocvar_g_monster_wyvern_attack_fireball_damagetime, this.projectiledeathtype);
+               Fire_AddDamage(it, own, 5 * MONSTER_SKILLMOD(own), autocvar_g_monster_wyvern_attack_fireball_damagetime, this.projectiledeathtype);
        });
 
        delete(this);
@@ -170,7 +134,7 @@ METHOD(Wyvern, mr_death, bool(Wyvern this, entity actor))
     return true;
 }
 #endif
-#ifndef MENUQC
+#ifdef GAMEQC
 METHOD(Wyvern, mr_anim, bool(Wyvern this, entity actor))
 {
     TC(Wyvern, this);
@@ -207,5 +171,3 @@ METHOD(Wyvern, mr_precache, bool(Wyvern this))
     return true;
 }
 #endif
-
-#endif
diff --git a/qcsrc/common/monsters/monster/wyvern.qh b/qcsrc/common/monsters/monster/wyvern.qh
new file mode 100644 (file)
index 0000000..0af84c1
--- /dev/null
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "../all.qh"
+
+#ifdef GAMEQC
+MODEL(MON_WYVERN, M_Model("wizard.mdl"));
+#endif
+
+CLASS(Wyvern, Monster)
+    ATTRIB(Wyvern, spawnflags, int, MONSTER_TYPE_FLY | MONSTER_SIZE_BROKEN | MON_FLAG_RANGED | MON_FLAG_RIDE);
+    ATTRIB(Wyvern, mins, vector, '-20 -20 -58');
+    ATTRIB(Wyvern, maxs, vector, '20 20 20');
+#ifdef GAMEQC
+    ATTRIB(Wyvern, m_model, Model, MDL_MON_WYVERN);
+#endif
+    ATTRIB(Wyvern, netname, string, "wyvern");
+    ATTRIB(Wyvern, monster_name, string, _("Wyvern"));
+ENDCLASS(Wyvern)
+
+REGISTER_MONSTER(WYVERN, NEW(Wyvern)) {
+#ifdef GAMEQC
+    this.mr_precache(this);
+#endif
+}
+
+#include <common/weapons/_all.qh>
+
+CLASS(WyvernAttack, PortoLaunch)
+/* flags     */ ATTRIB(WyvernAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* impulse   */ ATTRIB(WyvernAttack, impulse, int, 9);
+/* refname   */ ATTRIB(WyvernAttack, netname, string, "wyvern");
+/* wepname   */ ATTRIB(WyvernAttack, m_name, string, _("Wyvern attack"));
+ENDCLASS(WyvernAttack)
+REGISTER_WEAPON(WYVERN_ATTACK, NEW(WyvernAttack));
index fd270a1e1efaf2142ecea7a7fd0475b38c7ccae5..c48c2108fa2299b80eee1aebdccf5a7da5f4d21b 100644 (file)
@@ -1,30 +1,4 @@
-#ifndef ZOMBIE_H
-#define ZOMBIE_H
-
-#ifndef MENUQC
-MODEL(MON_ZOMBIE, M_Model("zombie.dpm"));
-#endif
-
-CLASS(Zombie, Monster)
-    ATTRIB(Zombie, spawnflags, int, MON_FLAG_MELEE | MON_FLAG_RIDE);
-    ATTRIB(Zombie, mins, vector, '-18 -18 -25');
-    ATTRIB(Zombie, maxs, vector, '18 18 47');
-#ifndef MENUQC
-    ATTRIB(Zombie, m_model, Model, MDL_MON_ZOMBIE);
-#endif
-    ATTRIB(Zombie, netname, string, "zombie");
-    ATTRIB(Zombie, monster_name, string, _("Zombie"));
-ENDCLASS(Zombie)
-
-REGISTER_MONSTER(ZOMBIE, NEW(Zombie)) {
-#ifndef MENUQC
-    this.mr_precache(this);
-#endif
-}
-
-#endif
-
-#ifdef IMPLEMENTATION
+#include "zombie.qh"
 
 #ifdef SVQC
 float autocvar_g_monster_zombie_health;
@@ -180,7 +154,7 @@ METHOD(Zombie, mr_death, bool(Zombie this, entity actor))
     return true;
 }
 #endif
-#ifndef MENUQC
+#ifdef GAMEQC
 METHOD(Zombie, mr_anim, bool(Zombie this, entity actor))
 {
     TC(Zombie, this);
@@ -234,5 +208,3 @@ METHOD(Zombie, mr_precache, bool(Zombie this))
     return true;
 }
 #endif
-
-#endif
diff --git a/qcsrc/common/monsters/monster/zombie.qh b/qcsrc/common/monsters/monster/zombie.qh
new file mode 100644 (file)
index 0000000..b52056e
--- /dev/null
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "../all.qh"
+
+#ifdef GAMEQC
+MODEL(MON_ZOMBIE, M_Model("zombie.dpm"));
+#endif
+
+CLASS(Zombie, Monster)
+    ATTRIB(Zombie, spawnflags, int, MON_FLAG_MELEE | MON_FLAG_RIDE);
+    ATTRIB(Zombie, mins, vector, '-18 -18 -25');
+    ATTRIB(Zombie, maxs, vector, '18 18 47');
+#ifdef GAMEQC
+    ATTRIB(Zombie, m_model, Model, MDL_MON_ZOMBIE);
+#endif
+    ATTRIB(Zombie, netname, string, "zombie");
+    ATTRIB(Zombie, monster_name, string, _("Zombie"));
+ENDCLASS(Zombie)
+
+REGISTER_MONSTER(ZOMBIE, NEW(Zombie)) {
+#ifdef GAMEQC
+    this.mr_precache(this);
+#endif
+}
diff --git a/qcsrc/common/monsters/spawn.qc b/qcsrc/common/monsters/spawn.qc
deleted file mode 100644 (file)
index 23fc845..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-    #include "../util.qh"
-    #include "all.qh"
-    #include "sv_monsters.qh"
-    #include "spawn.qh"
-    #include <server/autocvars.qh>
-    #include <server/defs.qh>
-#endif
-entity spawnmonster (string monster, float monster_id, entity spawnedby, entity own, vector orig, float respwn, float invincible, float moveflag)
-{
-       float i;
-       entity e = spawn();
-
-       e.spawnflags = MONSTERFLAG_SPAWNED;
-
-       if(!respwn) { e.spawnflags |= MONSTERFLAG_NORESPAWN; }
-       if(invincible) { e.spawnflags |= MONSTERFLAG_INVINCIBLE; }
-
-       setorigin(e, orig);
-
-       if(monster == "random")
-       {
-               RandomSelection_Init();
-               for(i = MON_FIRST; i <= MON_LAST; ++i)
-                       RandomSelection_Add(NULL, i, string_null, 1, 1);
-
-           monster_id = RandomSelection_chosen_float;
-       }
-       else if(monster != "")
-       {
-               float found = 0;
-               entity mon;
-               for(i = MON_FIRST; i <= MON_LAST; ++i)
-               {
-                       mon = get_monsterinfo(i);
-                       if(mon.netname == monster)
-                       {
-                               found = true;
-                               monster_id = mon.monsterid; // we have the monster, old monster id is no longer required
-                               break;
-                       }
-               }
-               if(!found)
-                       monster_id = ((monster_id > 0) ? monster_id : MON_FIRST);
-       }
-
-       e.realowner = spawnedby;
-
-       if(moveflag)
-               e.monster_moveflags = moveflag;
-
-       if(IS_PLAYER(spawnedby))
-       {
-               if(teamplay && autocvar_g_monsters_teams)
-                       e.team = spawnedby.team; // colors handled in spawn code
-
-               if(autocvar_g_monsters_owners)
-                       e.monster_follow = own; // using .owner makes the monster non-solid for its master
-
-               e.angles_y = spawnedby.angles_y;
-       }
-
-       // Monster_Spawn checks if monster is valid
-       Monster_Spawn(e, monster_id);
-
-       return e;
-}
diff --git a/qcsrc/common/monsters/spawn.qh b/qcsrc/common/monsters/spawn.qh
deleted file mode 100644 (file)
index 0aba5c1..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-entity spawnmonster (string monster, float monster_id, entity spawnedby, entity own, vector orig, float respwn, float invincible, float moveflag);
index c72c7461ed5e039f39b949c0c5a6543803e3b9f8..9ac1f4e14084f0adaa1ec8f40f2047ac14dd2ef9 100644 (file)
@@ -1,29 +1,27 @@
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-    #include <lib/warpzone/common.qh>
-    #include "../constants.qh"
-    #include "../teams.qh"
-    #include "../util.qh"
-    #include "all.qh"
-    #include "sv_monsters.qh"
-       #include "../physics/movelib.qh"
-    #include "../weapons/all.qh"
-    #include <server/autocvars.qh>
-    #include <server/defs.qh>
-    #include "../deathtypes/all.qh"
-    #include <server/mutators/all.qh>
-       #include <server/steerlib.qh>
-       #include "../turrets/sv_turrets.qh"
-       #include "../turrets/util.qh"
-    #include "../vehicles/all.qh"
-    #include <server/campaign.qh>
-    #include <server/command/common.qh>
-    #include <server/command/cmd.qh>
-       #include "../triggers/triggers.qh"
-    #include <lib/csqcmodel/sv_model.qh>
-    #include <server/round_handler.qh>
-#endif
+#include "sv_monsters.qh"
+
+#include <server/g_subs.qh>
+#include <lib/warpzone/common.qh>
+#include "../constants.qh"
+#include "../teams.qh"
+#include "../util.qh"
+#include "all.qh"
+#include "../physics/movelib.qh"
+#include "../weapons/_mod.qh"
+#include <server/autocvars.qh>
+#include <server/defs.qh>
+#include "../deathtypes/all.qh"
+#include <server/mutators/_mod.qh>
+#include <server/steerlib.qh>
+#include "../turrets/sv_turrets.qh"
+#include "../turrets/util.qh"
+#include "../vehicles/all.qh"
+#include <server/campaign.qh>
+#include <server/command/_mod.qh>
+#include "../triggers/triggers.qh"
+#include <lib/csqcmodel/sv_model.qh>
+#include <server/round_handler.qh>
+#include <server/weapons/_mod.qh>
 
 void monsters_setstatus(entity this)
 {
@@ -101,10 +99,10 @@ bool Monster_ValidTarget(entity this, entity targ)
                return false;
        }
 
-       traceline(this.origin + this.view_ofs, targ.origin, 0, this);
+       traceline(this.origin + this.view_ofs, targ.origin, MOVE_NOMONSTERS, this);
 
-       if((trace_fraction < 1) && (trace_ent != targ))
-               return false;
+       if(trace_fraction < 1)
+               return false; // solid
 
        if(autocvar_g_monsters_target_infront || (this.spawnflags & MONSTERFLAG_INFRONT))
        if(this.enemy != targ)
@@ -509,6 +507,8 @@ bool Monster_Respawn_Check(entity this)
 
 void Monster_Respawn(entity this) { Monster_Spawn(this, this.monsterid); }
 
+.vector        pos1, pos2;
+
 void Monster_Dead_Fade(entity this)
 {
        if(Monster_Respawn_Check(this))
@@ -544,6 +544,7 @@ void Monster_Use(entity this, entity actor, entity trigger)
        if(Monster_ValidTarget(this, actor)) { this.enemy = actor; }
 }
 
+.float pass_distance;
 vector Monster_Move_Target(entity this, entity targ)
 {
        // enemy is always preferred target
@@ -687,6 +688,7 @@ void Monster_CalculateVelocity(entity this, vector to, vector from, float turnra
 }
 
 .entity draggedby;
+.entity target2;
 
 void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
 {
@@ -1322,6 +1324,7 @@ bool Monster_Spawn(entity this, int mon_id)
        this.classname                  = "monster";
        this.takedamage                 = DAMAGE_AIM;
        this.bot_attack                 = true;
+       IL_PUSH(g_bot_targets, this);
        this.iscreature                 = true;
        this.teleportable               = true;
        this.damagedbycontents  = true;
diff --git a/qcsrc/common/monsters/sv_spawn.qc b/qcsrc/common/monsters/sv_spawn.qc
new file mode 100644 (file)
index 0000000..50373cc
--- /dev/null
@@ -0,0 +1,69 @@
+#include "sv_spawn.qh"
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+    #include "../util.qh"
+    #include "all.qh"
+    #include "sv_monsters.qh"
+    #include <server/autocvars.qh>
+    #include <server/defs.qh>
+#endif
+entity spawnmonster (string monster, float monster_id, entity spawnedby, entity own, vector orig, float respwn, float invincible, float moveflag)
+{
+       float i;
+       entity e = spawn();
+
+       e.spawnflags = MONSTERFLAG_SPAWNED;
+
+       if(!respwn) { e.spawnflags |= MONSTERFLAG_NORESPAWN; }
+       if(invincible) { e.spawnflags |= MONSTERFLAG_INVINCIBLE; }
+
+       setorigin(e, orig);
+
+       if(monster == "random")
+       {
+               RandomSelection_Init();
+               for(i = MON_FIRST; i <= MON_LAST; ++i)
+                       RandomSelection_Add(NULL, i, string_null, 1, 1);
+
+           monster_id = RandomSelection_chosen_float;
+       }
+       else if(monster != "")
+       {
+               float found = 0;
+               entity mon;
+               for(i = MON_FIRST; i <= MON_LAST; ++i)
+               {
+                       mon = get_monsterinfo(i);
+                       if(mon.netname == monster)
+                       {
+                               found = true;
+                               monster_id = mon.monsterid; // we have the monster, old monster id is no longer required
+                               break;
+                       }
+               }
+               if(!found)
+                       monster_id = ((monster_id > 0) ? monster_id : MON_FIRST);
+       }
+
+       e.realowner = spawnedby;
+
+       if(moveflag)
+               e.monster_moveflags = moveflag;
+
+       if(IS_PLAYER(spawnedby))
+       {
+               if(teamplay && autocvar_g_monsters_teams)
+                       e.team = spawnedby.team; // colors handled in spawn code
+
+               if(autocvar_g_monsters_owners)
+                       e.monster_follow = own; // using .owner makes the monster non-solid for its master
+
+               e.angles_y = spawnedby.angles_y;
+       }
+
+       // Monster_Spawn checks if monster is valid
+       Monster_Spawn(e, monster_id);
+
+       return e;
+}
diff --git a/qcsrc/common/monsters/sv_spawn.qh b/qcsrc/common/monsters/sv_spawn.qh
new file mode 100644 (file)
index 0000000..0aba5c1
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma once
+
+entity spawnmonster (string monster, float monster_id, entity spawnedby, entity own, vector orig, float respwn, float invincible, float moveflag);
index 8220b2d19540a75e8f6a2014fce6b88672e3e408..29d6deabb9dd39935fa31ab4fd69a16243d61f6d 100644 (file)
@@ -1,2 +1,3 @@
 // generated file; do not modify
-#include <common/mutators/all.qc>
+
+#include <common/mutators/mutator/_mod.inc>
index 5d6ac5628b0f1ca6b1b9e3cc67736ea55090f6ba..b19e9c4d70ff03b759cb9f4bd56c7dcbbf3990f3 100644 (file)
@@ -1,2 +1,3 @@
 // generated file; do not modify
-#include <common/mutators/all.qh>
+
+#include <common/mutators/mutator/_mod.qh>
diff --git a/qcsrc/common/mutators/all.inc b/qcsrc/common/mutators/all.inc
deleted file mode 100644 (file)
index 6225872..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#include "mutator/waypoints/module.inc"
-
-#include "mutator/itemstime.qc"
-#include "mutator/multijump/module.inc"
-#include "mutator/nades/module.inc"
-#include "mutator/superspec/module.inc"
-
-// completely self contained
-
-#include "mutator/bloodloss/module.inc"
-#include "mutator/breakablehook/module.inc"
-#include "mutator/buffs/module.inc"
-#include "mutator/bugrigs/module.inc"
-#include "mutator/campcheck/module.inc"
-#include "mutator/cloaked/module.inc"
-#include "mutator/damagetext/module.inc"
-#include "mutator/dodging/module.inc"
-#include "mutator/doublejump/module.inc"
-#include "mutator/globalforces/module.inc"
-#include "mutator/hook/module.inc"
-#include "mutator/instagib/module.inc"
-#include "mutator/invincibleproj/module.inc"
-#include "mutator/melee_only/module.inc"
-#include "mutator/midair/module.inc"
-#include "mutator/new_toys/module.inc"
-#include "mutator/nix/module.inc"
-#include "mutator/overkill/module.inc"
-#include "mutator/physical_items/module.inc"
-#include "mutator/pinata/module.inc"
-#include "mutator/random_gravity/module.inc"
-#include "mutator/rocketflying/module.inc"
-#include "mutator/rocketminsta/module.inc"
-#include "mutator/running_guns/module.inc"
-#include "mutator/sandbox/module.inc"
-#include "mutator/spawn_near_teammate/module.inc"
-#include "mutator/touchexplode/module.inc"
-#include "mutator/vampirehook/module.inc"
-#include "mutator/vampire/module.inc"
-#include "mutator/weaponarena_random/module.inc"
diff --git a/qcsrc/common/mutators/all.qc b/qcsrc/common/mutators/all.qc
deleted file mode 100644 (file)
index f0fc719..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "all.qh"
-
-#define IMPLEMENTATION
-#include "all.inc"
-#undef IMPLEMENTATION
diff --git a/qcsrc/common/mutators/all.qh b/qcsrc/common/mutators/all.qh
deleted file mode 100644 (file)
index ceb4b51..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef MUTATORS_ALL_H
-#define MUTATORS_ALL_H
-
-#include "all.inc"
-
-#endif
index 5187f7fe1ffeb12b8f397e170597ec398295b6ca..ee5dc4ab12b7ec974a2de6a508e0ac6086713eb4 100644 (file)
@@ -1,5 +1,4 @@
-#ifndef MUTATORS_BASE_H
-#define MUTATORS_BASE_H
+#pragma once
 
 const int CBC_ORDER_FIRST = 1;
 const int CBC_ORDER_LAST = 2;
@@ -168,7 +167,7 @@ bool Mutator_Add(Mutator mut);
 void Mutator_Remove(Mutator mut);
 bool mutator_log = false;
 
-#ifndef MENUQC
+#ifdef GAMEQC
 /** server mutators activate corresponding client mutators for all clients */
 REGISTER_NET_LINKED(Mutator)
 
@@ -322,5 +321,3 @@ STATIC_INIT_LATE(Mutators) {
 } MACRO_END
 
 #include "events.qh"
-
-#endif
index 0dbc9ea21857cffe72d144a258fbddc25e5dc837..6b16371a2cfa739a97325ad4a8f8c69a04c61657 100644 (file)
@@ -1,5 +1,4 @@
-#ifndef COMMON_MUTATORS_EVENTS_H
-#define COMMON_MUTATORS_EVENTS_H
+#pragma once
 
 #define EV_NO_ARGS(i, o)
 
@@ -104,5 +103,3 @@ MUTATOR_HOOKABLE(PM_Physics, EV_PM_Physics);
     /**/          o(string, MUTATOR_ARGV_1_string) \
     /**/
 MUTATOR_HOOKABLE(WeaponModel, EV_WeaponModel);
-
-#endif
index 30d67e34bcd8da1d5b971e5d4386584f40215b6b..294047d500527146349f13811e9c6368e297d53d 100644 (file)
@@ -1,2 +1,37 @@
 // generated file; do not modify
-#include <common/mutators/mutator/itemstime.qc>
+
+#include <common/mutators/mutator/bloodloss/_mod.inc>
+#include <common/mutators/mutator/breakablehook/_mod.inc>
+#include <common/mutators/mutator/buffs/_mod.inc>
+#include <common/mutators/mutator/bugrigs/_mod.inc>
+#include <common/mutators/mutator/campcheck/_mod.inc>
+#include <common/mutators/mutator/cloaked/_mod.inc>
+#include <common/mutators/mutator/damagetext/_mod.inc>
+#include <common/mutators/mutator/dodging/_mod.inc>
+#include <common/mutators/mutator/doublejump/_mod.inc>
+#include <common/mutators/mutator/globalforces/_mod.inc>
+#include <common/mutators/mutator/hook/_mod.inc>
+#include <common/mutators/mutator/instagib/_mod.inc>
+#include <common/mutators/mutator/invincibleproj/_mod.inc>
+#include <common/mutators/mutator/itemstime/_mod.inc>
+#include <common/mutators/mutator/melee_only/_mod.inc>
+#include <common/mutators/mutator/midair/_mod.inc>
+#include <common/mutators/mutator/multijump/_mod.inc>
+#include <common/mutators/mutator/nades/_mod.inc>
+#include <common/mutators/mutator/new_toys/_mod.inc>
+#include <common/mutators/mutator/nix/_mod.inc>
+#include <common/mutators/mutator/overkill/_mod.inc>
+#include <common/mutators/mutator/physical_items/_mod.inc>
+#include <common/mutators/mutator/pinata/_mod.inc>
+#include <common/mutators/mutator/random_gravity/_mod.inc>
+#include <common/mutators/mutator/rocketflying/_mod.inc>
+#include <common/mutators/mutator/rocketminsta/_mod.inc>
+#include <common/mutators/mutator/running_guns/_mod.inc>
+#include <common/mutators/mutator/sandbox/_mod.inc>
+#include <common/mutators/mutator/spawn_near_teammate/_mod.inc>
+#include <common/mutators/mutator/superspec/_mod.inc>
+#include <common/mutators/mutator/touchexplode/_mod.inc>
+#include <common/mutators/mutator/vampire/_mod.inc>
+#include <common/mutators/mutator/vampirehook/_mod.inc>
+#include <common/mutators/mutator/waypoints/_mod.inc>
+#include <common/mutators/mutator/weaponarena_random/_mod.inc>
index ac056ac68b127dd8ab36770bdbd3a885d14937f5..de43630bedbdd822f9afe88cdad9ebcbf64489e3 100644 (file)
@@ -1,2 +1,37 @@
 // generated file; do not modify
-#include <common/mutators/mutator/itemstime.qh>
+
+#include <common/mutators/mutator/bloodloss/_mod.qh>
+#include <common/mutators/mutator/breakablehook/_mod.qh>
+#include <common/mutators/mutator/buffs/_mod.qh>
+#include <common/mutators/mutator/bugrigs/_mod.qh>
+#include <common/mutators/mutator/campcheck/_mod.qh>
+#include <common/mutators/mutator/cloaked/_mod.qh>
+#include <common/mutators/mutator/damagetext/_mod.qh>
+#include <common/mutators/mutator/dodging/_mod.qh>
+#include <common/mutators/mutator/doublejump/_mod.qh>
+#include <common/mutators/mutator/globalforces/_mod.qh>
+#include <common/mutators/mutator/hook/_mod.qh>
+#include <common/mutators/mutator/instagib/_mod.qh>
+#include <common/mutators/mutator/invincibleproj/_mod.qh>
+#include <common/mutators/mutator/itemstime/_mod.qh>
+#include <common/mutators/mutator/melee_only/_mod.qh>
+#include <common/mutators/mutator/midair/_mod.qh>
+#include <common/mutators/mutator/multijump/_mod.qh>
+#include <common/mutators/mutator/nades/_mod.qh>
+#include <common/mutators/mutator/new_toys/_mod.qh>
+#include <common/mutators/mutator/nix/_mod.qh>
+#include <common/mutators/mutator/overkill/_mod.qh>
+#include <common/mutators/mutator/physical_items/_mod.qh>
+#include <common/mutators/mutator/pinata/_mod.qh>
+#include <common/mutators/mutator/random_gravity/_mod.qh>
+#include <common/mutators/mutator/rocketflying/_mod.qh>
+#include <common/mutators/mutator/rocketminsta/_mod.qh>
+#include <common/mutators/mutator/running_guns/_mod.qh>
+#include <common/mutators/mutator/sandbox/_mod.qh>
+#include <common/mutators/mutator/spawn_near_teammate/_mod.qh>
+#include <common/mutators/mutator/superspec/_mod.qh>
+#include <common/mutators/mutator/touchexplode/_mod.qh>
+#include <common/mutators/mutator/vampire/_mod.qh>
+#include <common/mutators/mutator/vampirehook/_mod.qh>
+#include <common/mutators/mutator/waypoints/_mod.qh>
+#include <common/mutators/mutator/weaponarena_random/_mod.qh>
index 16e6308acf9d39e466c350241b96d3ece7f990e6..768808db71f1cb41d9acf29090865a5c7d35a09c 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/bloodloss/bloodloss.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/bloodloss/sv_bloodloss.qc>
+#endif
index b1d45e2791b07d3e3d1b8572fed442328348f863..e6ad248c622d6aaad3d8f0e2b93744037e9c5577 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/bloodloss/bloodloss.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/bloodloss/sv_bloodloss.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/bloodloss/bloodloss.qc b/qcsrc/common/mutators/mutator/bloodloss/bloodloss.qc
deleted file mode 100644 (file)
index a335bf1..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(bloodloss, cvar("g_bloodloss"));
-
-.float bloodloss_timer;
-
-MUTATOR_HOOKFUNCTION(bloodloss, PlayerPreThink)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(IS_PLAYER(player))
-       if(player.health <= autocvar_g_bloodloss && !IS_DEAD(player))
-       {
-               PHYS_INPUT_BUTTON_CROUCH(player) = true;
-
-               if(time >= player.bloodloss_timer)
-               {
-                       if(player.vehicle)
-                               vehicles_exit(player.vehicle, VHEF_RELEASE);
-                       if(player.event_damage)
-                               player.event_damage(player, player, player, 1, DEATH_ROT.m_id, player.origin, '0 0 0');
-                       player.bloodloss_timer = time + 0.5 + random() * 0.5;
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(bloodloss, PlayerJump)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.health <= autocvar_g_bloodloss)
-               return true;
-}
-
-MUTATOR_HOOKFUNCTION(bloodloss, BuildMutatorsString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":bloodloss");
-}
-
-MUTATOR_HOOKFUNCTION(bloodloss, BuildMutatorsPrettyString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Blood loss");
-}
-#endif
diff --git a/qcsrc/common/mutators/mutator/bloodloss/module.inc b/qcsrc/common/mutators/mutator/bloodloss/module.inc
deleted file mode 100644 (file)
index d3f665a..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "bloodloss.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/bloodloss/sv_bloodloss.qc b/qcsrc/common/mutators/mutator/bloodloss/sv_bloodloss.qc
new file mode 100644 (file)
index 0000000..61b0c06
--- /dev/null
@@ -0,0 +1,43 @@
+#include "sv_bloodloss.qh"
+
+REGISTER_MUTATOR(bloodloss, cvar("g_bloodloss"));
+
+.float bloodloss_timer;
+
+MUTATOR_HOOKFUNCTION(bloodloss, PlayerPreThink)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(IS_PLAYER(player))
+       if(player.health <= autocvar_g_bloodloss && !IS_DEAD(player))
+       {
+               PHYS_INPUT_BUTTON_CROUCH(player) = true;
+
+               if(time >= player.bloodloss_timer)
+               {
+                       if(player.vehicle)
+                               vehicles_exit(player.vehicle, VHEF_RELEASE);
+                       if(player.event_damage)
+                               player.event_damage(player, player, player, 1, DEATH_ROT.m_id, player.origin, '0 0 0');
+                       player.bloodloss_timer = time + 0.5 + random() * 0.5;
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(bloodloss, PlayerJump)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.health <= autocvar_g_bloodloss)
+               return true;
+}
+
+MUTATOR_HOOKFUNCTION(bloodloss, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":bloodloss");
+}
+
+MUTATOR_HOOKFUNCTION(bloodloss, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Blood loss");
+}
diff --git a/qcsrc/common/mutators/mutator/bloodloss/sv_bloodloss.qh b/qcsrc/common/mutators/mutator/bloodloss/sv_bloodloss.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index bdbbae46cdd60b60bac6541367bce201df18930a..11a080ef4a5ae85b1e0ff0ac452d0dfb39f099ed 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/breakablehook/breakablehook.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/breakablehook/sv_breakablehook.qc>
+#endif
index 8a41908af314aa1c09d0d27f4fe95f1719f56322..f8b2d1bc653a7d6098ead487cb912ecda3606760 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/breakablehook/breakablehook.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/breakablehook/sv_breakablehook.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/breakablehook/breakablehook.qc b/qcsrc/common/mutators/mutator/breakablehook/breakablehook.qc
deleted file mode 100644 (file)
index ca266eb..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifdef IMPLEMENTATION
-#include <common/deathtypes/all.qh>
-#include <server/g_hook.qh>
-
-REGISTER_MUTATOR(breakablehook, cvar("g_breakablehook"));
-
-bool autocvar_g_breakablehook; // allow toggling mid match?
-bool autocvar_g_breakablehook_owner;
-
-MUTATOR_HOOKFUNCTION(breakablehook, PlayerDamage_Calculate)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-
-       if(frag_target.classname == "grapplinghook")
-       {
-               if((!autocvar_g_breakablehook)
-               || (!autocvar_g_breakablehook_owner && frag_attacker == frag_target.realowner)
-                       ) { M_ARGV(4, float) = 0; }
-
-               // hurt the owner of the hook
-               if(DIFF_TEAM(frag_attacker, frag_target.realowner))
-               {
-                       Damage (frag_target.realowner, frag_attacker, frag_attacker, 5, WEP_HOOK.m_id | HITTYPE_SPLASH, frag_target.realowner.origin, '0 0 0');
-                       RemoveGrapplingHook(frag_target.realowner);
-                       return; // dead
-               }
-       }
-}
-#endif
diff --git a/qcsrc/common/mutators/mutator/breakablehook/module.inc b/qcsrc/common/mutators/mutator/breakablehook/module.inc
deleted file mode 100644 (file)
index 484eb4c..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "breakablehook.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/breakablehook/sv_breakablehook.qc b/qcsrc/common/mutators/mutator/breakablehook/sv_breakablehook.qc
new file mode 100644 (file)
index 0000000..fdb0dc3
--- /dev/null
@@ -0,0 +1,30 @@
+#include "sv_breakablehook.qh"
+
+#include <common/deathtypes/all.qh>
+#include <server/g_hook.qh>
+
+REGISTER_MUTATOR(breakablehook, cvar("g_breakablehook"));
+
+bool autocvar_g_breakablehook; // allow toggling mid match?
+bool autocvar_g_breakablehook_owner;
+
+MUTATOR_HOOKFUNCTION(breakablehook, PlayerDamage_Calculate)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+
+       if(frag_target.classname == "grapplinghook")
+       {
+               if((!autocvar_g_breakablehook)
+               || (!autocvar_g_breakablehook_owner && frag_attacker == frag_target.realowner)
+                       ) { M_ARGV(4, float) = 0; }
+
+               // hurt the owner of the hook
+               if(DIFF_TEAM(frag_attacker, frag_target.realowner))
+               {
+                       Damage (frag_target.realowner, frag_attacker, frag_attacker, 5, WEP_HOOK.m_id | HITTYPE_SPLASH, frag_target.realowner.origin, '0 0 0');
+                       RemoveGrapplingHook(frag_target.realowner);
+                       return; // dead
+               }
+       }
+}
diff --git a/qcsrc/common/mutators/mutator/breakablehook/sv_breakablehook.qh b/qcsrc/common/mutators/mutator/breakablehook/sv_breakablehook.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index c06263a92f056dd90672e3c345a7c8515526b8f9..715a3acfccec654c443070f4a3e648f2ac90c1f1 100644 (file)
@@ -1,3 +1,8 @@
 // generated file; do not modify
-#include <common/mutators/mutator/buffs/all.qc>
 #include <common/mutators/mutator/buffs/buffs.qc>
+#ifdef CSQC
+    #include <common/mutators/mutator/buffs/cl_buffs.qc>
+#endif
+#ifdef SVQC
+    #include <common/mutators/mutator/buffs/sv_buffs.qc>
+#endif
index 2133c7250e51be50c318cf2773dead6aa20c8f6b..78217bb46e9f22873027e4c9cdb6bc6113f3035f 100644 (file)
@@ -1,3 +1,8 @@
 // generated file; do not modify
-#include <common/mutators/mutator/buffs/all.qh>
 #include <common/mutators/mutator/buffs/buffs.qh>
+#ifdef CSQC
+    #include <common/mutators/mutator/buffs/cl_buffs.qh>
+#endif
+#ifdef SVQC
+    #include <common/mutators/mutator/buffs/sv_buffs.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/buffs/all.qc b/qcsrc/common/mutators/mutator/buffs/all.qc
deleted file mode 100644 (file)
index b056751..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include "all.qh"
diff --git a/qcsrc/common/mutators/mutator/buffs/all.qh b/qcsrc/common/mutators/mutator/buffs/all.qh
deleted file mode 100644 (file)
index 79117c9..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef BUFFS_ALL_H
-#define BUFFS_ALL_H
-
-#include <common/teams.qh>
-#include <common/util.qh>
-
-REGISTER_WAYPOINT(Buff, _("Buff"), '1 0.5 0', 1);
-REGISTER_RADARICON(Buff, 1);
-
-REGISTRY(Buffs, BITS(5))
-#define Buffs_from(i) _Buffs_from(i, BUFF_Null)
-REGISTER_REGISTRY(Buffs)
-REGISTRY_CHECK(Buffs)
-
-#define REGISTER_BUFF(id) \
-    REGISTER(Buffs, BUFF_##id, m_id, NEW(Buff))
-
-#include <common/items/item/pickup.qh>
-CLASS(Buff, Pickup)
-       /** bit index */
-       ATTRIB(Buff, m_itemid, int, 0);
-       ATTRIB(Buff, m_name, string, "buff");
-       ATTRIB(Buff, m_color, vector, '1 1 1');
-       ATTRIB(Buff, m_prettyName, string, "Buff");
-       ATTRIB(Buff, m_skin, int, 0);
-       ATTRIB(Buff, m_sprite, string, "");
-       METHOD(Buff, display, void(entity this, void(string name, string icon) returns)) {
-               returns(this.m_prettyName, sprintf("/gfx/hud/%s/buff_%s", cvar_string("menu_skin"), this.m_name));
-       }
-#ifdef SVQC
-       METHOD(Buff, m_time, float(Buff this))
-       { return cvar(strcat("g_buffs_", this.netname, "_time")); }
-#endif
-ENDCLASS(Buff)
-
-STATIC_INIT(REGISTER_BUFFS) {
-    FOREACH(Buffs, true, {
-        it.netname = it.m_name; \
-        it.m_itemid = BIT(it.m_id - 1); \
-        it.m_sprite = strzone(strcat("buff-", it.m_name)); \
-    });
-}
-
-#ifdef SVQC
-       // .int buffs = _STAT(BUFFS);
-       void buff_Init(entity ent);
-       void buff_Init_Compat(entity ent, entity replacement);
-       #define BUFF_SPAWNFUNC(e, b, t) spawnfunc(item_buff_##e) { \
-               this.buffs = b.m_itemid; \
-               this.team = t; \
-               buff_Init(this); \
-       }
-       #define BUFF_SPAWNFUNCS(e, b)                       \
-                       BUFF_SPAWNFUNC(e,           b,  0)          \
-                       BUFF_SPAWNFUNC(e##_team1,   b,  NUM_TEAM_1) \
-                       BUFF_SPAWNFUNC(e##_team2,   b,  NUM_TEAM_2) \
-                       BUFF_SPAWNFUNC(e##_team3,   b,  NUM_TEAM_3) \
-                       BUFF_SPAWNFUNC(e##_team4,   b,  NUM_TEAM_4)
-       #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r) spawnfunc(item_##o) { buff_Init_Compat(this, r); }
-#else
-       #define BUFF_SPAWNFUNC(e, b, t)
-       #define BUFF_SPAWNFUNCS(e, b)
-       #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r)
-#endif
-
-REGISTER_BUFF(Null);
-BUFF_SPAWNFUNCS(random, BUFF_Null)
-
-#include "all.inc"
-
-#endif
index 29a0a39256ed85d45404a8f097603f0744efda2f..f38d39d61867ef56ec625271f7a330012b6a74e2 100644 (file)
-#ifndef MUTATOR_BUFFS_H
-#define MUTATOR_BUFFS_H
+#include "buffs.qh"
 
-#include "../instagib/module.inc"
-
-bool  autocvar_g_buffs_effects;
-float autocvar_g_buffs_waypoint_distance;
-bool autocvar_g_buffs_randomize;
-float autocvar_g_buffs_random_lifetime;
-bool autocvar_g_buffs_random_location;
-int autocvar_g_buffs_random_location_attempts;
-int autocvar_g_buffs_spawn_count;
-bool autocvar_g_buffs_replace_powerups;
-float autocvar_g_buffs_cooldown_activate;
-float autocvar_g_buffs_cooldown_respawn;
-float autocvar_g_buffs_resistance_blockpercent;
-float autocvar_g_buffs_medic_survive_chance;
-float autocvar_g_buffs_medic_survive_health;
-float autocvar_g_buffs_medic_rot;
-float autocvar_g_buffs_medic_max;
-float autocvar_g_buffs_medic_regen;
-float autocvar_g_buffs_medic_heal_amount = 15;
-float autocvar_g_buffs_medic_heal_delay = 1;
-float autocvar_g_buffs_medic_heal_range = 400;
-float autocvar_g_buffs_vengeance_damage_multiplier;
-float autocvar_g_buffs_bash_force;
-float autocvar_g_buffs_bash_force_self;
-float autocvar_g_buffs_disability_slowtime;
-float autocvar_g_buffs_disability_speed;
-float autocvar_g_buffs_disability_rate;
-float autocvar_g_buffs_disability_weaponspeed;
-float autocvar_g_buffs_speed_speed;
-float autocvar_g_buffs_speed_rate;
-float autocvar_g_buffs_speed_weaponspeed;
-float autocvar_g_buffs_speed_damage_take;
-float autocvar_g_buffs_speed_regen;
-float autocvar_g_buffs_vampire_damage_steal;
-float autocvar_g_buffs_invisible_alpha;
-float autocvar_g_buffs_jump_height;
-float autocvar_g_buffs_inferno_burntime_factor;
-float autocvar_g_buffs_inferno_burntime_min_time;
-float autocvar_g_buffs_inferno_burntime_target_damage;
-float autocvar_g_buffs_inferno_burntime_target_time;
-float autocvar_g_buffs_inferno_damagemultiplier;
-float autocvar_g_buffs_swapper_range;
-float autocvar_g_buffs_magnet_range_item;
-float autocvar_g_buffs_magnet_range_buff = 200;
-float autocvar_g_buffs_luck_chance = 0.15;
-float autocvar_g_buffs_luck_damagemultiplier = 3;
-
-// ammo
-.float buff_ammo_prev_infitems;
-.int buff_ammo_prev_clipload;
-// invisible
-.float buff_invisible_prev_alpha;
-// medic
-.float buff_medic_healtime;
-// disability
-.float buff_disability_time;
-.float buff_disability_effect_time;
-// common buff variables
-.float buff_effect_delay;
-
-// buff definitions
-.float buff_active;
-.float buff_activetime;
-.float buff_activetime_updated;
-.entity buff_waypoint;
-.int oldbuffs; // for updating effects
-.entity buff_model; // controls effects (TODO: make csqc)
-
-const vector BUFF_MIN = ('-16 -16 -20');
-const vector BUFF_MAX = ('16 16 20');
-
-// client side options
-.float cvar_cl_buffs_autoreplace;
-#endif
-
-#ifdef IMPLEMENTATION
-
-#include <common/triggers/target/music.qh>
-#include <common/gamemodes/all.qh>
-
-.float buff_time = _STAT(BUFF_TIME);
-void buffs_DelayedInit(entity this);
-
-REGISTER_MUTATOR(buffs, cvar("g_buffs"))
-{
-       MUTATOR_ONADD
-       {
-               InitializeEntity(NULL, buffs_DelayedInit, INITPRIO_FINDTARGET);
-       }
-}
-
-bool buffs_BuffModel_Customize(entity this, entity client)
-{
-       entity player, myowner;
-       bool same_team;
-
-       player = WaypointSprite_getviewentity(client);
-       myowner = this.owner;
-       same_team = (SAME_TEAM(player, myowner) || SAME_TEAM(player, myowner));
-
-       if(myowner.alpha <= 0.5 && !same_team && myowner.alpha != 0)
-               return false;
-
-       if(MUTATOR_CALLHOOK(BuffModel_Customize, this, player))
-               return false;
-
-       if(player == myowner || (IS_SPEC(client) && client.enemy == myowner))
-       {
-               // somewhat hide the model, but keep the glow
-               this.effects = 0;
-               this.alpha = -1;
-       }
-       else
-       {
-               this.effects = EF_FULLBRIGHT | EF_LOWPRECISION;
-               this.alpha = 1;
-       }
-       return true;
-}
-
-void buffs_BuffModel_Spawn(entity player)
-{
-       player.buff_model = spawn();
-       setmodel(player.buff_model, MDL_BUFF);
-       setsize(player.buff_model, '0 0 -40', '0 0 40');
-       setattachment(player.buff_model, player, "");
-       setorigin(player.buff_model, '0 0 1' * (player.buff_model.maxs.z * 1));
-       player.buff_model.owner = player;
-       player.buff_model.scale = 0.7;
-       player.buff_model.pflags = PFLAGS_FULLDYNAMIC;
-       player.buff_model.light_lev = 200;
-       setcefc(player.buff_model, buffs_BuffModel_Customize);
-}
-
-vector buff_GlowColor(entity buff)
-{
-       //if(buff.team) { return Team_ColorRGB(buff.team); }
-       return buff.m_color;
-}
-
-void buff_Effect(entity player, string eff)
-{
-       if(!autocvar_g_buffs_effects) { return; }
-
-       if(time >= player.buff_effect_delay)
-       {
-               Send_Effect_(eff, player.origin + ((player.mins + player.maxs) * 0.5), '0 0 0', 1);
-               player.buff_effect_delay = time + 0.05; // prevent spam
-       }
-}
-
-// buff item
-bool buff_Waypoint_visible_for_player(entity this, entity player, entity view)
-{
-       if(!this.owner.buff_active && !this.owner.buff_activetime)
-               return false;
-
-       if (view.buffs)
-       {
-               return view.cvar_cl_buffs_autoreplace == false || view.buffs != this.owner.buffs;
-       }
-
-       return WaypointSprite_visible_for_player(this, player, view);
-}
-
-void buff_Waypoint_Spawn(entity e)
-{
-       entity buff = buff_FirstFromFlags(e.buffs);
-       entity wp = WaypointSprite_Spawn(WP_Buff, 0, autocvar_g_buffs_waypoint_distance, e, '0 0 1' * e.maxs.z, NULL, e.team, e, buff_waypoint, true, RADARICON_Buff);
-       wp.wp_extra = buff.m_id;
-       WaypointSprite_UpdateTeamRadar(e.buff_waypoint, RADARICON_Buff, e.glowmod);
-       e.buff_waypoint.waypointsprite_visible_for_player = buff_Waypoint_visible_for_player;
-}
-
-void buff_SetCooldown(entity this, float cd)
-{
-       cd = max(0, cd);
-
-       if(!this.buff_waypoint)
-               buff_Waypoint_Spawn(this);
-
-       WaypointSprite_UpdateBuildFinished(this.buff_waypoint, time + cd);
-       this.buff_activetime = cd;
-       this.buff_active = !cd;
-}
-
-void buff_Respawn(entity this)
-{
-       if(gameover) { return; }
-
-       vector oldbufforigin = this.origin;
-       this.velocity = '0 0 200';
-
-       if(!MoveToRandomMapLocation(this, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY,
-               ((autocvar_g_buffs_random_location_attempts > 0) ? autocvar_g_buffs_random_location_attempts : 10), 1024, 256))
-       {
-               entity spot = SelectSpawnPoint(this, true);
-               setorigin(this, spot.origin);
-               this.velocity = ((randomvec() * 100) + '0 0 200');
-               this.angles = spot.angles;
-       }
-
-       tracebox(this.origin, this.mins * 1.5, this.maxs * 1.5, this.origin, MOVE_NOMONSTERS, this);
-
-       setorigin(this, trace_endpos); // attempt to unstick
-
-       set_movetype(this, MOVETYPE_TOSS);
-
-       makevectors(this.angles);
-       this.angles = '0 0 0';
-       if(autocvar_g_buffs_random_lifetime > 0)
-               this.lifetime = time + autocvar_g_buffs_random_lifetime;
-
-       Send_Effect(EFFECT_ELECTRO_COMBO, oldbufforigin + ((this.mins + this.maxs) * 0.5), '0 0 0', 1);
-       Send_Effect(EFFECT_ELECTRO_COMBO, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
-
-       WaypointSprite_Ping(this.buff_waypoint);
-
-       sound(this, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
-}
-
-void buff_Touch(entity this, entity toucher)
-{
-       if(gameover) { return; }
-
-       if(ITEM_TOUCH_NEEDKILL())
-       {
-               buff_Respawn(this);
-               return;
-       }
-
-       if((this.team && DIFF_TEAM(toucher, this))
-       || (STAT(FROZEN, toucher))
-       || (toucher.vehicle)
-       || (!this.buff_active)
-       )
-       {
-               // can't touch this
-               return;
-       }
-
-       if(MUTATOR_CALLHOOK(BuffTouch, this, toucher))
-               return;
-       toucher = M_ARGV(1, entity);
-
-       if(!IS_PLAYER(toucher))
-               return; // incase mutator changed toucher
-
-       if (toucher.buffs)
-       {
-               if (toucher.cvar_cl_buffs_autoreplace && toucher.buffs != this.buffs)
-               {
-                       int buffid = buff_FirstFromFlags(toucher.buffs).m_id;
-                       //Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_DROP, toucher.buffs);
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ITEM_BUFF_LOST, toucher.netname, buffid);
-
-                       toucher.buffs = 0;
-                       //sound(toucher, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
-               }
-               else { return; } // do nothing
-       }
-
-       this.owner = toucher;
-       this.buff_active = false;
-       this.lifetime = 0;
-       int buffid = buff_FirstFromFlags(this.buffs).m_id;
-       Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_GOT, buffid);
-       Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_INFO, INFO_ITEM_BUFF, toucher.netname, buffid);
-
-       Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
-       sound(toucher, CH_TRIGGER, SND_SHIELD_RESPAWN, VOL_BASE, ATTN_NORM);
-       toucher.buffs |= (this.buffs);
-}
-
-float buff_Available(entity buff)
-{
-       if (buff == BUFF_Null)
-               return false;
-       if (buff == BUFF_AMMO && ((start_items & IT_UNLIMITED_WEAPON_AMMO) || (start_items & IT_UNLIMITED_AMMO) || (cvar("g_melee_only"))))
-               return false;
-       if (buff == BUFF_VAMPIRE && cvar("g_vampire"))
-               return false;
-       return cvar(strcat("g_buffs_", buff.m_name));
-}
-
-.int buff_seencount;
-
-void buff_NewType(entity ent, float cb)
-{
-       RandomSelection_Init();
-       FOREACH(Buffs, buff_Available(it), LAMBDA(
-               it.buff_seencount += 1;
-               // if it's already been chosen, give it a lower priority
-               RandomSelection_Add(NULL, it.m_itemid, string_null, 1, max(0.2, 1 / it.buff_seencount));
-       ));
-       ent.buffs = RandomSelection_chosen_float;
-}
-
-void buff_Think(entity this)
-{
-       if(this.buffs != this.oldbuffs)
-       {
-               entity buff = buff_FirstFromFlags(this.buffs);
-               this.color = buff.m_color;
-               this.glowmod = buff_GlowColor(buff);
-               this.skin = buff.m_skin;
-
-               setmodel(this, MDL_BUFF);
-
-               if(this.buff_waypoint)
-               {
-                       //WaypointSprite_Disown(this.buff_waypoint, 1);
-                       WaypointSprite_Kill(this.buff_waypoint);
-                       buff_Waypoint_Spawn(this);
-                       if(this.buff_activetime)
-                               WaypointSprite_UpdateBuildFinished(this.buff_waypoint, time + this.buff_activetime - frametime);
-               }
-
-               this.oldbuffs = this.buffs;
-       }
-
-       if(!gameover)
-       if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime)
-       if(!this.buff_activetime_updated)
-       {
-               buff_SetCooldown(this, this.buff_activetime);
-               this.buff_activetime_updated = true;
-       }
-
-       if(!this.buff_active && !this.buff_activetime)
-       if(!this.owner || STAT(FROZEN, this.owner) || IS_DEAD(this.owner) || !this.owner.iscreature || !(this.owner.buffs & this.buffs))
-       {
-               buff_SetCooldown(this, autocvar_g_buffs_cooldown_respawn + frametime);
-               this.owner = NULL;
-               if(autocvar_g_buffs_randomize)
-                       buff_NewType(this, this.buffs);
-
-               if(autocvar_g_buffs_random_location || (this.spawnflags & 64))
-                       buff_Respawn(this);
-       }
-
-       if(this.buff_activetime)
-       if(!gameover)
-       if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime)
-       {
-               this.buff_activetime = max(0, this.buff_activetime - frametime);
-
-               if(!this.buff_activetime)
-               {
-                       this.buff_active = true;
-                       sound(this, CH_TRIGGER, SND_STRENGTH_RESPAWN, VOL_BASE, ATTN_NORM);
-                       Send_Effect(EFFECT_ITEM_RESPAWN, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
-               }
-       }
-
-       if(this.buff_active)
-       {
-               if(this.team && !this.buff_waypoint)
-                       buff_Waypoint_Spawn(this);
-
-               if(this.lifetime)
-               if(time >= this.lifetime)
-                       buff_Respawn(this);
-       }
-
-       this.nextthink = time;
-       //this.angles_y = time * 110.1;
-}
-
-void buff_Waypoint_Reset(entity this)
-{
-       WaypointSprite_Kill(this.buff_waypoint);
-
-       if(this.buff_activetime) { buff_Waypoint_Spawn(this); }
-}
-
-void buff_Reset(entity this)
-{
-       if(autocvar_g_buffs_randomize)
-               buff_NewType(this, this.buffs);
-       this.owner = NULL;
-       buff_SetCooldown(this, autocvar_g_buffs_cooldown_activate);
-       buff_Waypoint_Reset(this);
-       this.buff_activetime_updated = false;
-
-       if(autocvar_g_buffs_random_location || (this.spawnflags & 64))
-               buff_Respawn(this);
-}
-
-bool buff_Customize(entity this, entity client)
-{
-       entity player = WaypointSprite_getviewentity(client);
-       if(!this.buff_active || (this.team && DIFF_TEAM(player, this)))
-       {
-               this.alpha = 0.3;
-               if(this.effects & EF_FULLBRIGHT) { this.effects &= ~(EF_FULLBRIGHT); }
-               this.pflags = 0;
-       }
-       else
-       {
-               this.alpha = 1;
-               if(!(this.effects & EF_FULLBRIGHT)) { this.effects |= EF_FULLBRIGHT; }
-               this.light_lev = 220 + 36 * sin(time);
-               this.pflags = PFLAGS_FULLDYNAMIC;
-       }
-       return true;
-}
-
-void buff_Init(entity this)
-{
-       if(!cvar("g_buffs")) { delete(this); return; }
-
-       if(!teamplay && this.team) { this.team = 0; }
-
-       entity buff = buff_FirstFromFlags(this.buffs);
-
-       if(!this.buffs || buff_Available(buff))
-               buff_NewType(this, 0);
-
-       this.classname = "item_buff";
-       this.solid = SOLID_TRIGGER;
-       this.flags = FL_ITEM;
-       setthink(this, buff_Think);
-       settouch(this, buff_Touch);
-       this.reset = buff_Reset;
-       this.nextthink = time + 0.1;
-       this.gravity = 1;
-       set_movetype(this, MOVETYPE_TOSS);
-       this.scale = 1;
-       this.skin = buff.m_skin;
-       this.effects = EF_FULLBRIGHT | EF_STARDUST | EF_NOSHADOW;
-       this.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
-       setcefc(this, buff_Customize);
-       //this.gravity = 100;
-       this.color = buff.m_color;
-       this.glowmod = buff_GlowColor(this);
-       buff_SetCooldown(this, autocvar_g_buffs_cooldown_activate + game_starttime);
-       this.buff_active = !this.buff_activetime;
-       this.pflags = PFLAGS_FULLDYNAMIC;
-
-       if(this.spawnflags & 1)
-               this.noalign = true;
-
-       if(this.noalign)
-               set_movetype(this, MOVETYPE_NONE); // reset by random location
-
-       setmodel(this, MDL_BUFF);
-       setsize(this, BUFF_MIN, BUFF_MAX);
-
-       if(cvar("g_buffs_random_location") || (this.spawnflags & 64))
-               buff_Respawn(this);
-}
-
-void buff_Init_Compat(entity ent, entity replacement)
-{
-       if (ent.spawnflags & 2)
-               ent.team = NUM_TEAM_1;
-       else if (ent.spawnflags & 4)
-               ent.team = NUM_TEAM_2;
-
-       ent.buffs = replacement.m_itemid;
-
-       buff_Init(ent);
-}
-
-void buff_SpawnReplacement(entity ent, entity old)
-{
-       setorigin(ent, old.origin);
-       ent.angles = old.angles;
-       ent.noalign = (old.noalign || (old.spawnflags & 1));
-
-       buff_Init(ent);
-}
-
-void buff_Vengeance_DelayedDamage(entity this)
-{
-       if(this.enemy)
-               Damage(this.enemy, this.owner, this.owner, this.dmg, DEATH_BUFF.m_id, this.enemy.origin, '0 0 0');
-
-       delete(this);
-       return;
-}
-
-// note: only really useful in teamplay
-void buff_Medic_Heal(entity this)
-{
-       FOREACH_CLIENT(IS_PLAYER(it) && it != this && vdist(it.origin - this.origin, <=, autocvar_g_buffs_medic_heal_range),
-       {
-               if(SAME_TEAM(it, this))
-               if(it.health < autocvar_g_balance_health_regenstable)
-               {
-                       Send_Effect(EFFECT_HEALING, it.origin, '0 0 0', 1);
-                       it.health = bound(0, it.health + autocvar_g_buffs_medic_heal_amount, autocvar_g_balance_health_regenstable);
-               }
-       });
-}
-
-float buff_Inferno_CalculateTime(float x, float offset_x, float offset_y, float intersect_x, float intersect_y, float base)
-{
-       return offset_y + (intersect_y - offset_y) * logn(((x - offset_x) * ((base - 1) / intersect_x)) + 1, base);
-}
-
-// mutator hooks
-MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_SplitHealthArmor)
-{
-       entity frag_target = M_ARGV(2, entity);
-       float frag_deathtype = M_ARGV(6, float);
-       float frag_damage = M_ARGV(7, float);
-
-       if(frag_deathtype == DEATH_BUFF.m_id) { return; }
-
-       if(frag_target.buffs & BUFF_RESISTANCE.m_itemid)
-       {
-               vector v = healtharmor_applydamage(50, autocvar_g_buffs_resistance_blockpercent, frag_deathtype, frag_damage);
-               M_ARGV(4, float) = v.x; // take
-               M_ARGV(5, float) = v.y; // save
-       }
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_Calculate)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-       float frag_deathtype = M_ARGV(3, float);
-       float frag_damage = M_ARGV(4, float);
-       vector frag_force = M_ARGV(6, vector);
-
-       if(frag_deathtype == DEATH_BUFF.m_id) { return; }
-
-       if(frag_target.buffs & BUFF_SPEED.m_itemid)
-       if(frag_target != frag_attacker)
-               frag_damage *= autocvar_g_buffs_speed_damage_take;
-
-       if(frag_target.buffs & BUFF_MEDIC.m_itemid)
-       if((frag_target.health - frag_damage) <= 0)
-       if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
-       if(frag_attacker)
-       if(random() <= autocvar_g_buffs_medic_survive_chance)
-               frag_damage = max(5, frag_target.health - autocvar_g_buffs_medic_survive_health);
-
-       if(frag_target.buffs & BUFF_JUMP.m_itemid)
-       if(frag_deathtype == DEATH_FALL.m_id)
-               frag_damage = 0;
-
-       if(frag_target.buffs & BUFF_VENGEANCE.m_itemid)
-       if(frag_attacker)
-       if(frag_attacker != frag_target)
-       if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
-       {
-               entity dmgent = spawn();
-
-               dmgent.dmg = frag_damage * autocvar_g_buffs_vengeance_damage_multiplier;
-               dmgent.enemy = frag_attacker;
-               dmgent.owner = frag_target;
-               setthink(dmgent, buff_Vengeance_DelayedDamage);
-               dmgent.nextthink = time + 0.1;
-       }
-
-       if(frag_target.buffs & BUFF_BASH.m_itemid)
-       if(frag_attacker != frag_target)
-               frag_force = '0 0 0';
-
-       if(frag_attacker.buffs & BUFF_BASH.m_itemid)
-       if(frag_force)
-       if(frag_attacker == frag_target)
-               frag_force *= autocvar_g_buffs_bash_force_self;
-       else
-               frag_force *= autocvar_g_buffs_bash_force;
-
-       if(frag_attacker.buffs & BUFF_DISABILITY.m_itemid)
-       if(frag_target != frag_attacker)
-               frag_target.buff_disability_time = time + autocvar_g_buffs_disability_slowtime;
-
-       if(frag_target.buffs & BUFF_INFERNO.m_itemid)
-       {
-               if(frag_deathtype == DEATH_FIRE.m_id)
-                       frag_damage = 0;
-               if(frag_deathtype == DEATH_LAVA.m_id)
-                       frag_damage *= 0.5; // TODO: cvarize?
-       }
-
-       if(frag_attacker.buffs & BUFF_LUCK.m_itemid)
-       if(frag_attacker != frag_target)
-       if(autocvar_g_buffs_luck_damagemultiplier > 0)
-       if(random() <= autocvar_g_buffs_luck_chance)
-               frag_damage *= autocvar_g_buffs_luck_damagemultiplier;
-
-       if(frag_attacker.buffs & BUFF_INFERNO.m_itemid)
-       if(frag_target != frag_attacker) {
-               float btime = buff_Inferno_CalculateTime(
-                       frag_damage,
-                       0,
-                       autocvar_g_buffs_inferno_burntime_min_time,
-                       autocvar_g_buffs_inferno_burntime_target_damage,
-                       autocvar_g_buffs_inferno_burntime_target_time,
-                       autocvar_g_buffs_inferno_burntime_factor
-               );
-               Fire_AddDamage(frag_target, frag_attacker, (frag_damage * autocvar_g_buffs_inferno_damagemultiplier), btime, DEATH_BUFF.m_id);
-       }
-
-       // this... is ridiculous (TODO: fix!)
-       if(frag_attacker.buffs & BUFF_VAMPIRE.m_itemid)
-       if(!frag_target.vehicle)
-       if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
-       if(!IS_DEAD(frag_target))
-       if(IS_PLAYER(frag_target) || IS_MONSTER(frag_target))
-       if(frag_attacker != frag_target)
-       if(!STAT(FROZEN, frag_target))
-       if(frag_target.takedamage)
-       if(DIFF_TEAM(frag_attacker, frag_target))
-       {
-               frag_attacker.health = bound(0, frag_attacker.health + bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal, frag_target.health), g_pickup_healthsmall_max);
-               if(frag_target.armorvalue)
-                       frag_attacker.armorvalue = bound(0, frag_attacker.armorvalue + bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal, frag_target.armorvalue), g_pickup_armorsmall_max);
-       }
-
-       M_ARGV(4, float) = frag_damage;
-       M_ARGV(6, vector) = frag_force;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       player.buffs = 0;
-       player.buff_time = 0;
-       // reset timers here to prevent them continuing after re-spawn
-       player.buff_disability_time = 0;
-       player.buff_disability_effect_time = 0;
-}
-
-.float stat_sv_maxspeed;
-.float stat_sv_airspeedlimit_nonqw;
-.float stat_sv_jumpvelocity;
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.buffs & BUFF_SPEED.m_itemid)
-       {
-               player.stat_sv_maxspeed *= autocvar_g_buffs_speed_speed;
-               player.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_speed_speed;
-       }
-
-       if(time < player.buff_disability_time)
-       {
-               player.stat_sv_maxspeed *= autocvar_g_buffs_disability_speed;
-               player.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_disability_speed;
-       }
-
-       if(player.buffs & BUFF_JUMP.m_itemid)
-       {
-               // automatically reset, no need to worry
-               player.stat_sv_jumpvelocity = autocvar_g_buffs_jump_height;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerJump)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.buffs & BUFF_JUMP.m_itemid)
-               M_ARGV(1, float) = autocvar_g_buffs_jump_height;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, MonsterMove)
-{
-       entity mon = M_ARGV(0, entity);
-
-       if(time < mon.buff_disability_time)
-       {
-               M_ARGV(1, float) *= autocvar_g_buffs_disability_speed; // run speed
-               M_ARGV(2, float) *= autocvar_g_buffs_disability_speed; // walk speed
-       }
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerDies)
-{
-       entity frag_target = M_ARGV(2, entity);
-
-       if(frag_target.buffs)
-       {
-               int buffid = buff_FirstFromFlags(frag_target.buffs).m_id;
-               Send_Notification(NOTIF_ALL_EXCEPT, frag_target, MSG_INFO, INFO_ITEM_BUFF_LOST, frag_target.netname, buffid);
-               frag_target.buffs = 0;
-
-               if(frag_target.buff_model)
-               {
-                       delete(frag_target.buff_model);
-                       frag_target.buff_model = NULL;
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerUseKey, CBC_ORDER_FIRST)
-{
-       if(MUTATOR_RETURNVALUE || gameover) { return; }
-
-       entity player = M_ARGV(0, entity);
-
-       if(player.buffs)
-       {
-               int buffid = buff_FirstFromFlags(player.buffs).m_id;
-               Send_Notification(NOTIF_ONE, player, MSG_MULTI, ITEM_BUFF_DROP, buffid);
-               Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
-
-               player.buffs = 0;
-               player.buff_time = 0; // already notified
-               sound(player, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
-               return true;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(buffs, ForbidThrowCurrentWeapon)
-{
-       if(MUTATOR_RETURNVALUE || gameover) { return; }
-       entity player = M_ARGV(0, entity);
-
-       if(player.buffs & BUFF_SWAPPER.m_itemid)
-       {
-               float best_distance = autocvar_g_buffs_swapper_range;
-               entity closest = NULL;
-               FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
-                       if(!IS_DEAD(it) && !STAT(FROZEN, it) && !it.vehicle)
-                       if(DIFF_TEAM(it, player))
-                       {
-                               float test = vlen2(player.origin - it.origin);
-                               if(test <= best_distance * best_distance)
-                               {
-                                       best_distance = sqrt(test);
-                                       closest = it;
-                               }
-                       }
-               ));
-
-               if(closest)
-               {
-                       vector my_org, my_vel, my_ang, their_org, their_vel, their_ang;
-
-                       my_org = player.origin;
-                       my_vel = player.velocity;
-                       my_ang = player.angles;
-                       their_org = closest.origin;
-                       their_vel = closest.velocity;
-                       their_ang = closest.angles;
-
-                       Drop_Special_Items(closest);
-
-                       MUTATOR_CALLHOOK(PortalTeleport, player); // initiate flag dropper
-
-                       setorigin(player, their_org);
-                       setorigin(closest, my_org);
-
-                       closest.velocity = my_vel;
-                       closest.angles = my_ang;
-                       closest.fixangle = true;
-                       closest.oldorigin = my_org;
-                       closest.oldvelocity = my_vel;
-                       player.velocity = their_vel;
-                       player.angles = their_ang;
-                       player.fixangle = true;
-                       player.oldorigin = their_org;
-                       player.oldvelocity = their_vel;
-
-                       // set pusher so player gets the kill if they fall into void
-                       closest.pusher = player;
-                       closest.pushltime = time + autocvar_g_maxpushtime;
-                       closest.istypefrag = PHYS_INPUT_BUTTON_CHAT(closest);
-
-                       Send_Effect(EFFECT_ELECTRO_COMBO, their_org, '0 0 0', 1);
-                       Send_Effect(EFFECT_ELECTRO_COMBO, my_org, '0 0 0', 1);
-
-                       sound(player, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);
-                       sound(closest, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);
-
-                       // TODO: add a counter to handle how many times one can teleport, and a delay to prevent spam
-                       player.buffs = 0;
-                       return true;
-               }
-       }
-}
-
-bool buffs_RemovePlayer(entity player)
-{
-       if(player.buff_model)
-       {
-               delete(player.buff_model);
-               player.buff_model = NULL;
-       }
-
-       // also reset timers here to prevent them continuing after spectating
-       player.buff_disability_time = 0;
-       player.buff_disability_effect_time = 0;
-
-       return false;
-}
-MUTATOR_HOOKFUNCTION(buffs, MakePlayerObserver) { entity player = M_ARGV(0, entity); return buffs_RemovePlayer(player); }
-MUTATOR_HOOKFUNCTION(buffs, ClientDisconnect) { entity player = M_ARGV(0, entity); return buffs_RemovePlayer(player); }
-
-MUTATOR_HOOKFUNCTION(buffs, CustomizeWaypoint)
-{
-       entity wp = M_ARGV(0, entity);
-       entity player = M_ARGV(1, entity);
-
-       entity e = WaypointSprite_getviewentity(player);
-
-       // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
-       // but only apply this to real players, not to spectators
-       if((wp.owner.flags & FL_CLIENT) && (wp.owner.buffs & BUFF_INVISIBLE.m_itemid) && (e == player))
-       if(DIFF_TEAM(wp.owner, e))
-               return true;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, OnEntityPreSpawn, CBC_ORDER_LAST)
-{
-       entity ent = M_ARGV(0, entity);
-
-       if(autocvar_g_buffs_replace_powerups)
-       switch(ent.classname)
-       {
-               case "item_strength":
-               case "item_invincible":
-               {
-                       entity e = spawn();
-                       buff_SpawnReplacement(e, ent);
-                       return true;
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(buffs, WeaponRateFactor)
-{
-       entity player = M_ARGV(1, entity);
-
-       if(player.buffs & BUFF_SPEED.m_itemid)
-               M_ARGV(0, float) *= autocvar_g_buffs_speed_rate;
-
-       if(time < player.buff_disability_time)
-               M_ARGV(0, float) *= autocvar_g_buffs_disability_rate;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, WeaponSpeedFactor)
-{
-       entity player = M_ARGV(1, entity);
-
-       if(player.buffs & BUFF_SPEED.m_itemid)
-               M_ARGV(0, float) *= autocvar_g_buffs_speed_weaponspeed;
-
-       if(time < player.buff_disability_time)
-               M_ARGV(0, float) *= autocvar_g_buffs_disability_weaponspeed;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(gameover || IS_DEAD(player)) { return; }
-
-       if(time < player.buff_disability_time)
-       if(time >= player.buff_disability_effect_time)
-       {
-               Send_Effect(EFFECT_SMOKING, player.origin + ((player.mins + player.maxs) * 0.5), '0 0 0', 1);
-               player.buff_disability_effect_time = time + 0.5;
-       }
-
-       // handle buff lost status
-       // 1: notify everyone else
-       // 2: notify carrier as well
-       int buff_lost = 0;
-
-       if(player.buff_time && player.buffs)
-       if(time >= player.buff_time)
-       {
-               player.buff_time = 0;
-               buff_lost = 2;
-       }
-
-       if(STAT(FROZEN, player)) { buff_lost = 1; }
-
-       if(buff_lost)
-       {
-               if(player.buffs)
-               {
-                       int buffid = buff_FirstFromFlags(player.buffs).m_id;
-                       if(buff_lost == 2)
-                       {
-                               Send_Notification(NOTIF_ONE, player, MSG_MULTI, ITEM_BUFF_DROP, buffid); // TODO: special timeout message?
-                               sound(player, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
-                       }
-                       else
-                               Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
-                       player.buffs = 0;
-               }
-       }
-
-       if(player.buffs & BUFF_MAGNET.m_itemid)
-       {
-               vector pickup_size;
-               FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
-               {
-                       if(it.buffs)
-                               pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_buff;
-                       else
-                               pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_item;
-
-                       if(boxesoverlap(player.absmin - pickup_size, player.absmax + pickup_size, it.absmin, it.absmax))
-                       {
-                               if(gettouch(it))
-                                       gettouch(it)(it, player);
-                       }
-               });
-       }
-
-       if(player.buffs & BUFF_AMMO.m_itemid)
-       if(player.clip_size)
-               player.clip_load = player.(weapon_load[PS(player).m_switchweapon.m_id]) = player.clip_size;
-
-       if((player.buffs & BUFF_INVISIBLE.m_itemid) && (player.oldbuffs & BUFF_INVISIBLE.m_itemid))
-       if(player.alpha != autocvar_g_buffs_invisible_alpha)
-               player.alpha = autocvar_g_buffs_invisible_alpha; // powerups reset alpha, so we must enforce this (TODO)
-
-       if(player.buffs & BUFF_MEDIC.m_itemid)
-       if(time >= player.buff_medic_healtime)
-       {
-               buff_Medic_Heal(player);
-               player.buff_medic_healtime = time + autocvar_g_buffs_medic_heal_delay;
-       }
-
-#define BUFF_ONADD(b) if ( (player.buffs & (b).m_itemid) && !(player.oldbuffs & (b).m_itemid))
-#define BUFF_ONREM(b) if (!(player.buffs & (b).m_itemid) &&  (player.oldbuffs & (b).m_itemid))
-
-       if(player.buffs != player.oldbuffs)
-       {
-               entity buff = buff_FirstFromFlags(player.buffs);
-               float bufftime = buff != BUFF_Null ? buff.m_time(buff) : 0;
-               player.buff_time = (bufftime) ? time + bufftime : 0;
-
-               BUFF_ONADD(BUFF_AMMO)
-               {
-                       player.buff_ammo_prev_infitems = (player.items & IT_UNLIMITED_WEAPON_AMMO);
-                       player.items |= IT_UNLIMITED_WEAPON_AMMO;
-
-                       if(player.clip_load)
-                               player.buff_ammo_prev_clipload = player.clip_load;
-                       player.clip_load = player.(weapon_load[PS(player).m_switchweapon.m_id]) = player.clip_size;
-               }
-
-               BUFF_ONREM(BUFF_AMMO)
-               {
-                       if(player.buff_ammo_prev_infitems)
-                               player.items |= IT_UNLIMITED_WEAPON_AMMO;
-                       else
-                               player.items &= ~IT_UNLIMITED_WEAPON_AMMO;
-
-                       if(player.buff_ammo_prev_clipload)
-                               player.clip_load = player.buff_ammo_prev_clipload;
-               }
-
-               BUFF_ONADD(BUFF_INVISIBLE)
-               {
-                       if(time < player.strength_finished && g_instagib)
-                               player.alpha = autocvar_g_instagib_invis_alpha;
-                       else
-                               player.alpha = player.buff_invisible_prev_alpha;
-                       player.alpha = autocvar_g_buffs_invisible_alpha;
-               }
-
-               BUFF_ONREM(BUFF_INVISIBLE)
-                       player.alpha = player.buff_invisible_prev_alpha;
-
-               player.oldbuffs = player.buffs;
-               if(player.buffs)
-               {
-                       if(!player.buff_model)
-                               buffs_BuffModel_Spawn(player);
-
-                       player.buff_model.color = buff.m_color;
-                       player.buff_model.glowmod = buff_GlowColor(player.buff_model);
-                       player.buff_model.skin = buff.m_skin;
-
-                       player.effects |= EF_NOSHADOW;
-               }
-               else
-               {
-                       delete(player.buff_model);
-                       player.buff_model = NULL;
-
-                       player.effects &= ~(EF_NOSHADOW);
-               }
-       }
-
-       if(player.buff_model)
-       {
-               player.buff_model.effects = player.effects;
-               player.buff_model.effects |= EF_LOWPRECISION;
-               player.buff_model.effects = player.buff_model.effects & EFMASK_CHEAP; // eat performance
-
-               player.buff_model.alpha = player.alpha;
-       }
-
-#undef BUFF_ONADD
-#undef BUFF_ONREM
-}
-
-MUTATOR_HOOKFUNCTION(buffs, SpectateCopy)
-{
-       entity spectatee = M_ARGV(0, entity);
-       entity client = M_ARGV(1, entity);
-
-       client.buffs = spectatee.buffs;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, VehicleEnter)
-{
-       entity player = M_ARGV(0, entity);
-       entity veh = M_ARGV(1, entity);
-
-       veh.buffs = player.buffs;
-       player.buffs = 0;
-       veh.buff_time = max(0, player.buff_time - time);
-       player.buff_time = 0;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, VehicleExit)
-{
-       entity player = M_ARGV(0, entity);
-       entity veh = M_ARGV(1, entity);
-
-       player.buffs = player.oldbuffs = veh.buffs;
-       veh.buffs = 0;
-       player.buff_time = time + veh.buff_time;
-       veh.buff_time = 0;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerRegen)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.buffs & BUFF_MEDIC.m_itemid)
-       {
-               M_ARGV(2, float) = autocvar_g_buffs_medic_rot; // rot_mod
-               M_ARGV(4, float) = M_ARGV(1, float) = autocvar_g_buffs_medic_max; // limit_mod = max_mod
-               M_ARGV(2, float) = autocvar_g_buffs_medic_regen; // regen_mod
-       }
-
-       if(player.buffs & BUFF_SPEED.m_itemid)
-               M_ARGV(2, float) = autocvar_g_buffs_speed_regen; // regen_mod
-}
-
-REPLICATE(cvar_cl_buffs_autoreplace, bool, "cl_buffs_autoreplace");
-
-MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":Buffs");
-}
-
-MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsPrettyString)
+string BUFF_NAME(int i)
 {
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Buffs");
+    Buff b = Buffs_from(i);
+    return sprintf("%s%s", rgb_to_hexcolor(b.m_color), b.m_prettyName);
 }
 
-void buffs_DelayedInit(entity this)
+entity buff_FirstFromFlags(int _buffs)
 {
-       if(autocvar_g_buffs_spawn_count > 0)
-       if(find(NULL, classname, "item_buff") == NULL)
-       {
-               float i;
-               for(i = 0; i < autocvar_g_buffs_spawn_count; ++i)
-               {
-                       entity e = spawn();
-                       e.spawnflags |= 64; // always randomize
-                       e.velocity = randomvec() * 250; // this gets reset anyway if random location works
-                       buff_Init(e);
-               }
-       }
+    if (flags)
+    {
+        FOREACH(Buffs, it.m_itemid & _buffs, LAMBDA(return it));
+    }
+    return BUFF_Null;
 }
-#endif
diff --git a/qcsrc/common/mutators/mutator/buffs/buffs.qh b/qcsrc/common/mutators/mutator/buffs/buffs.qh
new file mode 100644 (file)
index 0000000..ae76d9f
--- /dev/null
@@ -0,0 +1,70 @@
+#pragma once
+
+#include <common/teams.qh>
+#include <common/util.qh>
+
+#ifdef GAMEQC
+REGISTER_WAYPOINT(Buff, _("Buff"), '1 0.5 0', 1);
+REGISTER_RADARICON(Buff, 1);
+#endif
+
+REGISTRY(Buffs, BITS(5))
+#define Buffs_from(i) _Buffs_from(i, BUFF_Null)
+REGISTER_REGISTRY(Buffs)
+REGISTRY_CHECK(Buffs)
+
+#define REGISTER_BUFF(id) \
+    REGISTER(Buffs, BUFF_##id, m_id, NEW(Buff))
+
+#include <common/items/item/pickup.qh>
+CLASS(Buff, Pickup)
+       /** bit index */
+       ATTRIB(Buff, m_itemid, int, 0);
+       ATTRIB(Buff, m_name, string, "buff");
+       ATTRIB(Buff, m_color, vector, '1 1 1');
+       ATTRIB(Buff, m_prettyName, string, "Buff");
+       ATTRIB(Buff, m_skin, int, 0);
+       ATTRIB(Buff, m_sprite, string, "");
+       METHOD(Buff, display, void(entity this, void(string name, string icon) returns)) {
+               returns(this.m_prettyName, sprintf("/gfx/hud/%s/buff_%s", cvar_string("menu_skin"), this.m_name));
+       }
+#ifdef SVQC
+       METHOD(Buff, m_time, float(Buff this))
+       { return cvar(strcat("g_buffs_", this.netname, "_time")); }
+#endif
+ENDCLASS(Buff)
+
+STATIC_INIT(REGISTER_BUFFS) {
+    FOREACH(Buffs, true, {
+        it.netname = it.m_name; \
+        it.m_itemid = BIT(it.m_id - 1); \
+        it.m_sprite = strzone(strcat("buff-", it.m_name)); \
+    });
+}
+
+#ifdef SVQC
+       // .int buffs = _STAT(BUFFS);
+       void buff_Init(entity ent);
+       void buff_Init_Compat(entity ent, entity replacement);
+       #define BUFF_SPAWNFUNC(e, b, t) spawnfunc(item_buff_##e) { \
+               this.buffs = b.m_itemid; \
+               this.team = t; \
+               buff_Init(this); \
+       }
+       #define BUFF_SPAWNFUNCS(e, b)                       \
+                       BUFF_SPAWNFUNC(e,           b,  0)          \
+                       BUFF_SPAWNFUNC(e##_team1,   b,  NUM_TEAM_1) \
+                       BUFF_SPAWNFUNC(e##_team2,   b,  NUM_TEAM_2) \
+                       BUFF_SPAWNFUNC(e##_team3,   b,  NUM_TEAM_3) \
+                       BUFF_SPAWNFUNC(e##_team4,   b,  NUM_TEAM_4)
+       #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r) spawnfunc(item_##o) { buff_Init_Compat(this, r); }
+#else
+       #define BUFF_SPAWNFUNC(e, b, t)
+       #define BUFF_SPAWNFUNCS(e, b)
+       #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r)
+#endif
+
+REGISTER_BUFF(Null);
+BUFF_SPAWNFUNCS(random, BUFF_Null)
+
+#include "all.inc"
diff --git a/qcsrc/common/mutators/mutator/buffs/cl_buffs.qc b/qcsrc/common/mutators/mutator/buffs/cl_buffs.qc
new file mode 100644 (file)
index 0000000..ca14753
--- /dev/null
@@ -0,0 +1,22 @@
+#include "cl_buffs.qh"
+
+REGISTER_MUTATOR(cl_buffs, true);
+MUTATOR_HOOKFUNCTION(cl_buffs, HUD_Powerups_add)
+{
+    int allBuffs = STAT(BUFFS);
+    FOREACH(Buffs, it.m_itemid & allBuffs, LAMBDA(
+               addPowerupItem(it.m_prettyName, strcat("buff_", it.m_name), it.m_color, bound(0, STAT(BUFF_TIME) - time, 99), 60);
+       ));
+}
+MUTATOR_HOOKFUNCTION(cl_buffs, WP_Format)
+{
+    entity this = M_ARGV(0, entity);
+    string s = M_ARGV(1, string);
+    if (s == WP_Buff.netname || s == RADARICON_Buff.netname)
+    {
+        Buff b = Buffs_from(this.wp_extra);
+        M_ARGV(2, vector) = b.m_color;
+        M_ARGV(3, string) = b.m_prettyName;
+        return true;
+    }
+}
diff --git a/qcsrc/common/mutators/mutator/buffs/cl_buffs.qh b/qcsrc/common/mutators/mutator/buffs/cl_buffs.qh
new file mode 100644 (file)
index 0000000..c939022
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma once
+
+#include "buffs.qh"
diff --git a/qcsrc/common/mutators/mutator/buffs/module.inc b/qcsrc/common/mutators/mutator/buffs/module.inc
deleted file mode 100644 (file)
index c248928..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#include "all.qc"
-#ifdef SVQC
-#include "buffs.qc"
-#endif
-
-#ifdef IMPLEMENTATION
-
-string BUFF_NAME(int i)
-{
-    Buff b = Buffs_from(i);
-    return sprintf("%s%s", rgb_to_hexcolor(b.m_color), b.m_prettyName);
-}
-
-entity buff_FirstFromFlags(int _buffs)
-{
-    if (flags)
-    {
-        FOREACH(Buffs, it.m_itemid & _buffs, LAMBDA(return it));
-    }
-    return BUFF_Null;
-}
-
-#ifdef CSQC
-REGISTER_MUTATOR(cl_buffs, true);
-MUTATOR_HOOKFUNCTION(cl_buffs, HUD_Powerups_add)
-{
-    int allBuffs = STAT(BUFFS);
-    FOREACH(Buffs, it.m_itemid & allBuffs, LAMBDA(
-               addPowerupItem(it.m_prettyName, strcat("buff_", it.m_name), it.m_color, bound(0, STAT(BUFF_TIME) - time, 99), 60);
-       ));
-}
-MUTATOR_HOOKFUNCTION(cl_buffs, WP_Format)
-{
-    entity this = M_ARGV(0, entity);
-    string s = M_ARGV(1, string);
-    if (s == WP_Buff.netname || s == RADARICON_Buff.netname)
-    {
-        Buff b = Buffs_from(this.wp_extra);
-        M_ARGV(2, vector) = b.m_color;
-        M_ARGV(3, string) = b.m_prettyName;
-        return true;
-    }
-}
-
-#endif
-#endif
diff --git a/qcsrc/common/mutators/mutator/buffs/sv_buffs.qc b/qcsrc/common/mutators/mutator/buffs/sv_buffs.qc
new file mode 100644 (file)
index 0000000..82fa2d3
--- /dev/null
@@ -0,0 +1,1006 @@
+#include "sv_buffs.qh"
+
+#include <common/triggers/target/music.qh>
+#include <common/gamemodes/_mod.qh>
+
+.float buff_time = _STAT(BUFF_TIME);
+void buffs_DelayedInit(entity this);
+
+REGISTER_MUTATOR(buffs, cvar("g_buffs"))
+{
+       MUTATOR_ONADD
+       {
+               InitializeEntity(NULL, buffs_DelayedInit, INITPRIO_FINDTARGET);
+       }
+}
+
+bool buffs_BuffModel_Customize(entity this, entity client)
+{
+       entity player, myowner;
+       bool same_team;
+
+       player = WaypointSprite_getviewentity(client);
+       myowner = this.owner;
+       same_team = (SAME_TEAM(player, myowner) || SAME_TEAM(player, myowner));
+
+       if(myowner.alpha <= 0.5 && !same_team && myowner.alpha != 0)
+               return false;
+
+       if(MUTATOR_CALLHOOK(BuffModel_Customize, this, player))
+               return false;
+
+       if(player == myowner || (IS_SPEC(client) && client.enemy == myowner))
+       {
+               // somewhat hide the model, but keep the glow
+               this.effects = 0;
+               this.alpha = -1;
+       }
+       else
+       {
+               this.effects = EF_FULLBRIGHT | EF_LOWPRECISION;
+               this.alpha = 1;
+       }
+       return true;
+}
+
+void buffs_BuffModel_Spawn(entity player)
+{
+       player.buff_model = spawn();
+       setmodel(player.buff_model, MDL_BUFF);
+       setsize(player.buff_model, '0 0 -40', '0 0 40');
+       setattachment(player.buff_model, player, "");
+       setorigin(player.buff_model, '0 0 1' * (player.buff_model.maxs.z * 1));
+       player.buff_model.owner = player;
+       player.buff_model.scale = 0.7;
+       player.buff_model.pflags = PFLAGS_FULLDYNAMIC;
+       player.buff_model.light_lev = 200;
+       setcefc(player.buff_model, buffs_BuffModel_Customize);
+}
+
+vector buff_GlowColor(entity buff)
+{
+       //if(buff.team) { return Team_ColorRGB(buff.team); }
+       return buff.m_color;
+}
+
+void buff_Effect(entity player, string eff)
+{
+       if(!autocvar_g_buffs_effects) { return; }
+
+       if(time >= player.buff_effect_delay)
+       {
+               Send_Effect_(eff, player.origin + ((player.mins + player.maxs) * 0.5), '0 0 0', 1);
+               player.buff_effect_delay = time + 0.05; // prevent spam
+       }
+}
+
+// buff item
+bool buff_Waypoint_visible_for_player(entity this, entity player, entity view)
+{
+       if(!this.owner.buff_active && !this.owner.buff_activetime)
+               return false;
+
+       if (view.buffs)
+       {
+               return view.cvar_cl_buffs_autoreplace == false || view.buffs != this.owner.buffs;
+       }
+
+       return WaypointSprite_visible_for_player(this, player, view);
+}
+
+void buff_Waypoint_Spawn(entity e)
+{
+       entity buff = buff_FirstFromFlags(e.buffs);
+       entity wp = WaypointSprite_Spawn(WP_Buff, 0, autocvar_g_buffs_waypoint_distance, e, '0 0 1' * e.maxs.z, NULL, e.team, e, buff_waypoint, true, RADARICON_Buff);
+       wp.wp_extra = buff.m_id;
+       WaypointSprite_UpdateTeamRadar(e.buff_waypoint, RADARICON_Buff, e.glowmod);
+       e.buff_waypoint.waypointsprite_visible_for_player = buff_Waypoint_visible_for_player;
+}
+
+void buff_SetCooldown(entity this, float cd)
+{
+       cd = max(0, cd);
+
+       if(!this.buff_waypoint)
+               buff_Waypoint_Spawn(this);
+
+       WaypointSprite_UpdateBuildFinished(this.buff_waypoint, time + cd);
+       this.buff_activetime = cd;
+       this.buff_active = !cd;
+}
+
+void buff_Respawn(entity this)
+{
+       if(gameover) { return; }
+
+       vector oldbufforigin = this.origin;
+       this.velocity = '0 0 200';
+
+       if(!MoveToRandomMapLocation(this, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY,
+               ((autocvar_g_buffs_random_location_attempts > 0) ? autocvar_g_buffs_random_location_attempts : 10), 1024, 256))
+       {
+               entity spot = SelectSpawnPoint(this, true);
+               setorigin(this, spot.origin);
+               this.velocity = ((randomvec() * 100) + '0 0 200');
+               this.angles = spot.angles;
+       }
+
+       tracebox(this.origin, this.mins * 1.5, this.maxs * 1.5, this.origin, MOVE_NOMONSTERS, this);
+
+       setorigin(this, trace_endpos); // attempt to unstick
+
+       set_movetype(this, MOVETYPE_TOSS);
+
+       makevectors(this.angles);
+       this.angles = '0 0 0';
+       if(autocvar_g_buffs_random_lifetime > 0)
+               this.lifetime = time + autocvar_g_buffs_random_lifetime;
+
+       Send_Effect(EFFECT_ELECTRO_COMBO, oldbufforigin + ((this.mins + this.maxs) * 0.5), '0 0 0', 1);
+       Send_Effect(EFFECT_ELECTRO_COMBO, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
+
+       WaypointSprite_Ping(this.buff_waypoint);
+
+       sound(this, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
+}
+
+void buff_Touch(entity this, entity toucher)
+{
+       if(gameover) { return; }
+
+       if(ITEM_TOUCH_NEEDKILL())
+       {
+               buff_Respawn(this);
+               return;
+       }
+
+       if((this.team && DIFF_TEAM(toucher, this))
+       || (STAT(FROZEN, toucher))
+       || (toucher.vehicle)
+       || (!this.buff_active)
+       )
+       {
+               // can't touch this
+               return;
+       }
+
+       if(MUTATOR_CALLHOOK(BuffTouch, this, toucher))
+               return;
+       toucher = M_ARGV(1, entity);
+
+       if(!IS_PLAYER(toucher))
+               return; // incase mutator changed toucher
+
+       if (toucher.buffs)
+       {
+               if (toucher.cvar_cl_buffs_autoreplace && toucher.buffs != this.buffs)
+               {
+                       int buffid = buff_FirstFromFlags(toucher.buffs).m_id;
+                       //Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_DROP, toucher.buffs);
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ITEM_BUFF_LOST, toucher.netname, buffid);
+
+                       toucher.buffs = 0;
+                       //sound(toucher, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
+               }
+               else { return; } // do nothing
+       }
+
+       this.owner = toucher;
+       this.buff_active = false;
+       this.lifetime = 0;
+       int buffid = buff_FirstFromFlags(this.buffs).m_id;
+       Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_GOT, buffid);
+       Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_INFO, INFO_ITEM_BUFF, toucher.netname, buffid);
+
+       Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
+       sound(toucher, CH_TRIGGER, SND_SHIELD_RESPAWN, VOL_BASE, ATTN_NORM);
+       toucher.buffs |= (this.buffs);
+}
+
+float buff_Available(entity buff)
+{
+       if (buff == BUFF_Null)
+               return false;
+       if (buff == BUFF_AMMO && ((start_items & IT_UNLIMITED_WEAPON_AMMO) || (start_items & IT_UNLIMITED_AMMO) || (cvar("g_melee_only"))))
+               return false;
+       if (buff == BUFF_VAMPIRE && cvar("g_vampire"))
+               return false;
+       return cvar(strcat("g_buffs_", buff.m_name));
+}
+
+.int buff_seencount;
+
+void buff_NewType(entity ent, float cb)
+{
+       RandomSelection_Init();
+       FOREACH(Buffs, buff_Available(it), LAMBDA(
+               it.buff_seencount += 1;
+               // if it's already been chosen, give it a lower priority
+               RandomSelection_Add(NULL, it.m_itemid, string_null, 1, max(0.2, 1 / it.buff_seencount));
+       ));
+       ent.buffs = RandomSelection_chosen_float;
+}
+
+void buff_Think(entity this)
+{
+       if(this.buffs != this.oldbuffs)
+       {
+               entity buff = buff_FirstFromFlags(this.buffs);
+               this.color = buff.m_color;
+               this.glowmod = buff_GlowColor(buff);
+               this.skin = buff.m_skin;
+
+               setmodel(this, MDL_BUFF);
+
+               if(this.buff_waypoint)
+               {
+                       //WaypointSprite_Disown(this.buff_waypoint, 1);
+                       WaypointSprite_Kill(this.buff_waypoint);
+                       buff_Waypoint_Spawn(this);
+                       if(this.buff_activetime)
+                               WaypointSprite_UpdateBuildFinished(this.buff_waypoint, time + this.buff_activetime - frametime);
+               }
+
+               this.oldbuffs = this.buffs;
+       }
+
+       if(!gameover)
+       if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime)
+       if(!this.buff_activetime_updated)
+       {
+               buff_SetCooldown(this, this.buff_activetime);
+               this.buff_activetime_updated = true;
+       }
+
+       if(!this.buff_active && !this.buff_activetime)
+       if(!this.owner || STAT(FROZEN, this.owner) || IS_DEAD(this.owner) || !this.owner.iscreature || !(this.owner.buffs & this.buffs))
+       {
+               buff_SetCooldown(this, autocvar_g_buffs_cooldown_respawn + frametime);
+               this.owner = NULL;
+               if(autocvar_g_buffs_randomize)
+                       buff_NewType(this, this.buffs);
+
+               if(autocvar_g_buffs_random_location || (this.spawnflags & 64))
+                       buff_Respawn(this);
+       }
+
+       if(this.buff_activetime)
+       if(!gameover)
+       if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime)
+       {
+               this.buff_activetime = max(0, this.buff_activetime - frametime);
+
+               if(!this.buff_activetime)
+               {
+                       this.buff_active = true;
+                       sound(this, CH_TRIGGER, SND_STRENGTH_RESPAWN, VOL_BASE, ATTN_NORM);
+                       Send_Effect(EFFECT_ITEM_RESPAWN, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
+               }
+       }
+
+       if(this.buff_active)
+       {
+               if(this.team && !this.buff_waypoint)
+                       buff_Waypoint_Spawn(this);
+
+               if(this.lifetime)
+               if(time >= this.lifetime)
+                       buff_Respawn(this);
+       }
+
+       this.nextthink = time;
+       //this.angles_y = time * 110.1;
+}
+
+void buff_Waypoint_Reset(entity this)
+{
+       WaypointSprite_Kill(this.buff_waypoint);
+
+       if(this.buff_activetime) { buff_Waypoint_Spawn(this); }
+}
+
+void buff_Reset(entity this)
+{
+       if(autocvar_g_buffs_randomize)
+               buff_NewType(this, this.buffs);
+       this.owner = NULL;
+       buff_SetCooldown(this, autocvar_g_buffs_cooldown_activate);
+       buff_Waypoint_Reset(this);
+       this.buff_activetime_updated = false;
+
+       if(autocvar_g_buffs_random_location || (this.spawnflags & 64))
+               buff_Respawn(this);
+}
+
+bool buff_Customize(entity this, entity client)
+{
+       entity player = WaypointSprite_getviewentity(client);
+       if(!this.buff_active || (this.team && DIFF_TEAM(player, this)))
+       {
+               this.alpha = 0.3;
+               if(this.effects & EF_FULLBRIGHT) { this.effects &= ~(EF_FULLBRIGHT); }
+               this.pflags = 0;
+       }
+       else
+       {
+               this.alpha = 1;
+               if(!(this.effects & EF_FULLBRIGHT)) { this.effects |= EF_FULLBRIGHT; }
+               this.light_lev = 220 + 36 * sin(time);
+               this.pflags = PFLAGS_FULLDYNAMIC;
+       }
+       return true;
+}
+
+void buff_Init(entity this)
+{
+       if(!cvar("g_buffs")) { delete(this); return; }
+
+       if(!teamplay && this.team) { this.team = 0; }
+
+       entity buff = buff_FirstFromFlags(this.buffs);
+
+       if(!this.buffs || buff_Available(buff))
+               buff_NewType(this, 0);
+
+       this.classname = "item_buff";
+       this.solid = SOLID_TRIGGER;
+       this.flags = FL_ITEM;
+       this.bot_pickup = true;
+       this.bot_pickupevalfunc = commodity_pickupevalfunc;
+       this.bot_pickupbasevalue = 1000;
+       IL_PUSH(g_items, this);
+       setthink(this, buff_Think);
+       settouch(this, buff_Touch);
+       this.reset = buff_Reset;
+       this.nextthink = time + 0.1;
+       this.gravity = 1;
+       set_movetype(this, MOVETYPE_TOSS);
+       this.scale = 1;
+       this.skin = buff.m_skin;
+       this.effects = EF_FULLBRIGHT | EF_STARDUST | EF_NOSHADOW;
+       this.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
+       setcefc(this, buff_Customize);
+       //this.gravity = 100;
+       this.color = buff.m_color;
+       this.glowmod = buff_GlowColor(this);
+       buff_SetCooldown(this, autocvar_g_buffs_cooldown_activate + game_starttime);
+       this.buff_active = !this.buff_activetime;
+       this.pflags = PFLAGS_FULLDYNAMIC;
+
+       if(this.spawnflags & 1)
+               this.noalign = true;
+
+       if(this.noalign)
+               set_movetype(this, MOVETYPE_NONE); // reset by random location
+
+       setmodel(this, MDL_BUFF);
+       setsize(this, BUFF_MIN, BUFF_MAX);
+
+       if(cvar("g_buffs_random_location") || (this.spawnflags & 64))
+               buff_Respawn(this);
+}
+
+void buff_Init_Compat(entity ent, entity replacement)
+{
+       if (ent.spawnflags & 2)
+               ent.team = NUM_TEAM_1;
+       else if (ent.spawnflags & 4)
+               ent.team = NUM_TEAM_2;
+
+       ent.buffs = replacement.m_itemid;
+
+       buff_Init(ent);
+}
+
+void buff_SpawnReplacement(entity ent, entity old)
+{
+       setorigin(ent, old.origin);
+       ent.angles = old.angles;
+       ent.noalign = (old.noalign || (old.spawnflags & 1));
+
+       buff_Init(ent);
+}
+
+void buff_Vengeance_DelayedDamage(entity this)
+{
+       if(this.enemy)
+               Damage(this.enemy, this.owner, this.owner, this.dmg, DEATH_BUFF.m_id, this.enemy.origin, '0 0 0');
+
+       delete(this);
+       return;
+}
+
+// note: only really useful in teamplay
+void buff_Medic_Heal(entity this)
+{
+       FOREACH_CLIENT(IS_PLAYER(it) && it != this && vdist(it.origin - this.origin, <=, autocvar_g_buffs_medic_heal_range),
+       {
+               if(SAME_TEAM(it, this))
+               if(it.health < autocvar_g_balance_health_regenstable)
+               {
+                       Send_Effect(EFFECT_HEALING, it.origin, '0 0 0', 1);
+                       it.health = bound(0, it.health + autocvar_g_buffs_medic_heal_amount, autocvar_g_balance_health_regenstable);
+               }
+       });
+}
+
+float buff_Inferno_CalculateTime(float x, float offset_x, float offset_y, float intersect_x, float intersect_y, float base)
+{
+       return offset_y + (intersect_y - offset_y) * logn(((x - offset_x) * ((base - 1) / intersect_x)) + 1, base);
+}
+
+// mutator hooks
+MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_SplitHealthArmor)
+{
+       entity frag_target = M_ARGV(2, entity);
+       float frag_deathtype = M_ARGV(6, float);
+       float frag_damage = M_ARGV(7, float);
+
+       if(frag_deathtype == DEATH_BUFF.m_id) { return; }
+
+       if(frag_target.buffs & BUFF_RESISTANCE.m_itemid)
+       {
+               vector v = healtharmor_applydamage(50, autocvar_g_buffs_resistance_blockpercent, frag_deathtype, frag_damage);
+               M_ARGV(4, float) = v.x; // take
+               M_ARGV(5, float) = v.y; // save
+       }
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_Calculate)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       float frag_deathtype = M_ARGV(3, float);
+       float frag_damage = M_ARGV(4, float);
+       vector frag_force = M_ARGV(6, vector);
+
+       if(frag_deathtype == DEATH_BUFF.m_id) { return; }
+
+       if(frag_target.buffs & BUFF_SPEED.m_itemid)
+       if(frag_target != frag_attacker)
+               frag_damage *= autocvar_g_buffs_speed_damage_take;
+
+       if(frag_target.buffs & BUFF_MEDIC.m_itemid)
+       if((frag_target.health - frag_damage) <= 0)
+       if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
+       if(frag_attacker)
+       if(random() <= autocvar_g_buffs_medic_survive_chance)
+               frag_damage = max(5, frag_target.health - autocvar_g_buffs_medic_survive_health);
+
+       if(frag_target.buffs & BUFF_JUMP.m_itemid)
+       if(frag_deathtype == DEATH_FALL.m_id)
+               frag_damage = 0;
+
+       if(frag_target.buffs & BUFF_VENGEANCE.m_itemid)
+       if(frag_attacker)
+       if(frag_attacker != frag_target)
+       if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
+       {
+               entity dmgent = spawn();
+
+               dmgent.dmg = frag_damage * autocvar_g_buffs_vengeance_damage_multiplier;
+               dmgent.enemy = frag_attacker;
+               dmgent.owner = frag_target;
+               setthink(dmgent, buff_Vengeance_DelayedDamage);
+               dmgent.nextthink = time + 0.1;
+       }
+
+       if(frag_target.buffs & BUFF_BASH.m_itemid)
+       if(frag_attacker != frag_target)
+               frag_force = '0 0 0';
+
+       if(frag_attacker.buffs & BUFF_BASH.m_itemid)
+       if(frag_force)
+       if(frag_attacker == frag_target)
+               frag_force *= autocvar_g_buffs_bash_force_self;
+       else
+               frag_force *= autocvar_g_buffs_bash_force;
+
+       if(frag_attacker.buffs & BUFF_DISABILITY.m_itemid)
+       if(frag_target != frag_attacker)
+               frag_target.buff_disability_time = time + autocvar_g_buffs_disability_slowtime;
+
+       if(frag_target.buffs & BUFF_INFERNO.m_itemid)
+       {
+               if(frag_deathtype == DEATH_FIRE.m_id)
+                       frag_damage = 0;
+               if(frag_deathtype == DEATH_LAVA.m_id)
+                       frag_damage *= 0.5; // TODO: cvarize?
+       }
+
+       if(frag_attacker.buffs & BUFF_LUCK.m_itemid)
+       if(frag_attacker != frag_target)
+       if(autocvar_g_buffs_luck_damagemultiplier > 0)
+       if(random() <= autocvar_g_buffs_luck_chance)
+               frag_damage *= autocvar_g_buffs_luck_damagemultiplier;
+
+       if(frag_attacker.buffs & BUFF_INFERNO.m_itemid)
+       if(frag_target != frag_attacker) {
+               float btime = buff_Inferno_CalculateTime(
+                       frag_damage,
+                       0,
+                       autocvar_g_buffs_inferno_burntime_min_time,
+                       autocvar_g_buffs_inferno_burntime_target_damage,
+                       autocvar_g_buffs_inferno_burntime_target_time,
+                       autocvar_g_buffs_inferno_burntime_factor
+               );
+               Fire_AddDamage(frag_target, frag_attacker, (frag_damage * autocvar_g_buffs_inferno_damagemultiplier), btime, DEATH_BUFF.m_id);
+       }
+
+       // this... is ridiculous (TODO: fix!)
+       if(frag_attacker.buffs & BUFF_VAMPIRE.m_itemid)
+       if(!frag_target.vehicle)
+       if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
+       if(!IS_DEAD(frag_target))
+       if(IS_PLAYER(frag_target) || IS_MONSTER(frag_target))
+       if(frag_attacker != frag_target)
+       if(!STAT(FROZEN, frag_target))
+       if(frag_target.takedamage)
+       if(DIFF_TEAM(frag_attacker, frag_target))
+       {
+               frag_attacker.health = bound(0, frag_attacker.health + bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal, frag_target.health), g_pickup_healthsmall_max);
+               if(frag_target.armorvalue)
+                       frag_attacker.armorvalue = bound(0, frag_attacker.armorvalue + bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal, frag_target.armorvalue), g_pickup_armorsmall_max);
+       }
+
+       M_ARGV(4, float) = frag_damage;
+       M_ARGV(6, vector) = frag_force;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       player.buffs = 0;
+       player.buff_time = 0;
+       // reset timers here to prevent them continuing after re-spawn
+       player.buff_disability_time = 0;
+       player.buff_disability_effect_time = 0;
+}
+
+.float stat_sv_maxspeed;
+.float stat_sv_airspeedlimit_nonqw;
+.float stat_sv_jumpvelocity;
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.buffs & BUFF_SPEED.m_itemid)
+       {
+               player.stat_sv_maxspeed *= autocvar_g_buffs_speed_speed;
+               player.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_speed_speed;
+       }
+
+       if(time < player.buff_disability_time)
+       {
+               player.stat_sv_maxspeed *= autocvar_g_buffs_disability_speed;
+               player.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_disability_speed;
+       }
+
+       if(player.buffs & BUFF_JUMP.m_itemid)
+       {
+               // automatically reset, no need to worry
+               player.stat_sv_jumpvelocity = autocvar_g_buffs_jump_height;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerJump)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.buffs & BUFF_JUMP.m_itemid)
+               M_ARGV(1, float) = autocvar_g_buffs_jump_height;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, MonsterMove)
+{
+       entity mon = M_ARGV(0, entity);
+
+       if(time < mon.buff_disability_time)
+       {
+               M_ARGV(1, float) *= autocvar_g_buffs_disability_speed; // run speed
+               M_ARGV(2, float) *= autocvar_g_buffs_disability_speed; // walk speed
+       }
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerDies)
+{
+       entity frag_target = M_ARGV(2, entity);
+
+       if(frag_target.buffs)
+       {
+               int buffid = buff_FirstFromFlags(frag_target.buffs).m_id;
+               Send_Notification(NOTIF_ALL_EXCEPT, frag_target, MSG_INFO, INFO_ITEM_BUFF_LOST, frag_target.netname, buffid);
+               frag_target.buffs = 0;
+
+               if(frag_target.buff_model)
+               {
+                       delete(frag_target.buff_model);
+                       frag_target.buff_model = NULL;
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerUseKey, CBC_ORDER_FIRST)
+{
+       if(MUTATOR_RETURNVALUE || gameover) { return; }
+
+       entity player = M_ARGV(0, entity);
+
+       if(player.buffs)
+       {
+               int buffid = buff_FirstFromFlags(player.buffs).m_id;
+               Send_Notification(NOTIF_ONE, player, MSG_MULTI, ITEM_BUFF_DROP, buffid);
+               Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
+
+               player.buffs = 0;
+               player.buff_time = 0; // already notified
+               sound(player, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
+               return true;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(buffs, ForbidThrowCurrentWeapon)
+{
+       if(MUTATOR_RETURNVALUE || gameover) { return; }
+       entity player = M_ARGV(0, entity);
+
+       if(player.buffs & BUFF_SWAPPER.m_itemid)
+       {
+               float best_distance = autocvar_g_buffs_swapper_range;
+               entity closest = NULL;
+               FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
+                       if(!IS_DEAD(it) && !STAT(FROZEN, it) && !it.vehicle)
+                       if(DIFF_TEAM(it, player))
+                       {
+                               float test = vlen2(player.origin - it.origin);
+                               if(test <= best_distance * best_distance)
+                               {
+                                       best_distance = sqrt(test);
+                                       closest = it;
+                               }
+                       }
+               ));
+
+               if(closest)
+               {
+                       vector my_org, my_vel, my_ang, their_org, their_vel, their_ang;
+
+                       my_org = player.origin;
+                       my_vel = player.velocity;
+                       my_ang = player.angles;
+                       their_org = closest.origin;
+                       their_vel = closest.velocity;
+                       their_ang = closest.angles;
+
+                       Drop_Special_Items(closest);
+
+                       MUTATOR_CALLHOOK(PortalTeleport, player); // initiate flag dropper
+
+                       setorigin(player, their_org);
+                       setorigin(closest, my_org);
+
+                       closest.velocity = my_vel;
+                       closest.angles = my_ang;
+                       closest.fixangle = true;
+                       closest.oldorigin = my_org;
+                       closest.oldvelocity = my_vel;
+                       player.velocity = their_vel;
+                       player.angles = their_ang;
+                       player.fixangle = true;
+                       player.oldorigin = their_org;
+                       player.oldvelocity = their_vel;
+
+                       // set pusher so player gets the kill if they fall into void
+                       closest.pusher = player;
+                       closest.pushltime = time + autocvar_g_maxpushtime;
+                       closest.istypefrag = PHYS_INPUT_BUTTON_CHAT(closest);
+
+                       Send_Effect(EFFECT_ELECTRO_COMBO, their_org, '0 0 0', 1);
+                       Send_Effect(EFFECT_ELECTRO_COMBO, my_org, '0 0 0', 1);
+
+                       sound(player, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);
+                       sound(closest, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);
+
+                       // TODO: add a counter to handle how many times one can teleport, and a delay to prevent spam
+                       player.buffs = 0;
+                       return true;
+               }
+       }
+}
+
+bool buffs_RemovePlayer(entity player)
+{
+       if(player.buff_model)
+       {
+               delete(player.buff_model);
+               player.buff_model = NULL;
+       }
+
+       // also reset timers here to prevent them continuing after spectating
+       player.buff_disability_time = 0;
+       player.buff_disability_effect_time = 0;
+
+       return false;
+}
+MUTATOR_HOOKFUNCTION(buffs, MakePlayerObserver) { entity player = M_ARGV(0, entity); return buffs_RemovePlayer(player); }
+MUTATOR_HOOKFUNCTION(buffs, ClientDisconnect) { entity player = M_ARGV(0, entity); return buffs_RemovePlayer(player); }
+
+MUTATOR_HOOKFUNCTION(buffs, CustomizeWaypoint)
+{
+       entity wp = M_ARGV(0, entity);
+       entity player = M_ARGV(1, entity);
+
+       entity e = WaypointSprite_getviewentity(player);
+
+       // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
+       // but only apply this to real players, not to spectators
+       if((wp.owner.flags & FL_CLIENT) && (wp.owner.buffs & BUFF_INVISIBLE.m_itemid) && (e == player))
+       if(DIFF_TEAM(wp.owner, e))
+               return true;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, OnEntityPreSpawn, CBC_ORDER_LAST)
+{
+       entity ent = M_ARGV(0, entity);
+
+       if(autocvar_g_buffs_replace_powerups)
+       switch(ent.classname)
+       {
+               case "item_strength":
+               case "item_invincible":
+               {
+                       entity e = spawn();
+                       buff_SpawnReplacement(e, ent);
+                       return true;
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(buffs, WeaponRateFactor)
+{
+       entity player = M_ARGV(1, entity);
+
+       if(player.buffs & BUFF_SPEED.m_itemid)
+               M_ARGV(0, float) *= autocvar_g_buffs_speed_rate;
+
+       if(time < player.buff_disability_time)
+               M_ARGV(0, float) *= autocvar_g_buffs_disability_rate;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, WeaponSpeedFactor)
+{
+       entity player = M_ARGV(1, entity);
+
+       if(player.buffs & BUFF_SPEED.m_itemid)
+               M_ARGV(0, float) *= autocvar_g_buffs_speed_weaponspeed;
+
+       if(time < player.buff_disability_time)
+               M_ARGV(0, float) *= autocvar_g_buffs_disability_weaponspeed;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(gameover || IS_DEAD(player)) { return; }
+
+       if(time < player.buff_disability_time)
+       if(time >= player.buff_disability_effect_time)
+       {
+               Send_Effect(EFFECT_SMOKING, player.origin + ((player.mins + player.maxs) * 0.5), '0 0 0', 1);
+               player.buff_disability_effect_time = time + 0.5;
+       }
+
+       // handle buff lost status
+       // 1: notify everyone else
+       // 2: notify carrier as well
+       int buff_lost = 0;
+
+       if(player.buff_time && player.buffs)
+       if(time >= player.buff_time)
+       {
+               player.buff_time = 0;
+               buff_lost = 2;
+       }
+
+       if(STAT(FROZEN, player)) { buff_lost = 1; }
+
+       if(buff_lost)
+       {
+               if(player.buffs)
+               {
+                       int buffid = buff_FirstFromFlags(player.buffs).m_id;
+                       if(buff_lost == 2)
+                       {
+                               Send_Notification(NOTIF_ONE, player, MSG_MULTI, ITEM_BUFF_DROP, buffid); // TODO: special timeout message?
+                               sound(player, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
+                       }
+                       else
+                               Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
+                       player.buffs = 0;
+               }
+       }
+
+       if(player.buffs & BUFF_MAGNET.m_itemid)
+       {
+               vector pickup_size;
+               IL_EACH(g_items, it.classname != "item_flag_team" && it.classname != "item_kh_key",
+               {
+                       if(it.buffs)
+                               pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_buff;
+                       else
+                               pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_item;
+
+                       if(boxesoverlap(player.absmin - pickup_size, player.absmax + pickup_size, it.absmin, it.absmax))
+                       {
+                               if(gettouch(it))
+                                       gettouch(it)(it, player);
+                       }
+               });
+       }
+
+       if(player.buffs & BUFF_AMMO.m_itemid)
+       if(player.clip_size)
+               player.clip_load = player.(weapon_load[PS(player).m_switchweapon.m_id]) = player.clip_size;
+
+       if((player.buffs & BUFF_INVISIBLE.m_itemid) && (player.oldbuffs & BUFF_INVISIBLE.m_itemid))
+       if(player.alpha != autocvar_g_buffs_invisible_alpha)
+               player.alpha = autocvar_g_buffs_invisible_alpha; // powerups reset alpha, so we must enforce this (TODO)
+
+       if(player.buffs & BUFF_MEDIC.m_itemid)
+       if(time >= player.buff_medic_healtime)
+       {
+               buff_Medic_Heal(player);
+               player.buff_medic_healtime = time + autocvar_g_buffs_medic_heal_delay;
+       }
+
+#define BUFF_ONADD(b) if ( (player.buffs & (b).m_itemid) && !(player.oldbuffs & (b).m_itemid))
+#define BUFF_ONREM(b) if (!(player.buffs & (b).m_itemid) &&  (player.oldbuffs & (b).m_itemid))
+
+       if(player.buffs != player.oldbuffs)
+       {
+               entity buff = buff_FirstFromFlags(player.buffs);
+               float bufftime = buff != BUFF_Null ? buff.m_time(buff) : 0;
+               player.buff_time = (bufftime) ? time + bufftime : 0;
+
+               BUFF_ONADD(BUFF_AMMO)
+               {
+                       player.buff_ammo_prev_infitems = (player.items & IT_UNLIMITED_WEAPON_AMMO);
+                       player.items |= IT_UNLIMITED_WEAPON_AMMO;
+
+                       if(player.clip_load)
+                               player.buff_ammo_prev_clipload = player.clip_load;
+                       player.clip_load = player.(weapon_load[PS(player).m_switchweapon.m_id]) = player.clip_size;
+               }
+
+               BUFF_ONREM(BUFF_AMMO)
+               {
+                       if(player.buff_ammo_prev_infitems)
+                               player.items |= IT_UNLIMITED_WEAPON_AMMO;
+                       else
+                               player.items &= ~IT_UNLIMITED_WEAPON_AMMO;
+
+                       if(player.buff_ammo_prev_clipload)
+                               player.clip_load = player.buff_ammo_prev_clipload;
+               }
+
+               BUFF_ONADD(BUFF_INVISIBLE)
+               {
+                       if(time < player.strength_finished && g_instagib)
+                               player.alpha = autocvar_g_instagib_invis_alpha;
+                       else
+                               player.alpha = player.buff_invisible_prev_alpha;
+                       player.alpha = autocvar_g_buffs_invisible_alpha;
+               }
+
+               BUFF_ONREM(BUFF_INVISIBLE)
+                       player.alpha = player.buff_invisible_prev_alpha;
+
+               player.oldbuffs = player.buffs;
+               if(player.buffs)
+               {
+                       if(!player.buff_model)
+                               buffs_BuffModel_Spawn(player);
+
+                       player.buff_model.color = buff.m_color;
+                       player.buff_model.glowmod = buff_GlowColor(player.buff_model);
+                       player.buff_model.skin = buff.m_skin;
+
+                       player.effects |= EF_NOSHADOW;
+               }
+               else
+               {
+                       delete(player.buff_model);
+                       player.buff_model = NULL;
+
+                       player.effects &= ~(EF_NOSHADOW);
+               }
+       }
+
+       if(player.buff_model)
+       {
+               player.buff_model.effects = player.effects;
+               player.buff_model.effects |= EF_LOWPRECISION;
+               player.buff_model.effects = player.buff_model.effects & EFMASK_CHEAP; // eat performance
+
+               player.buff_model.alpha = player.alpha;
+       }
+
+#undef BUFF_ONADD
+#undef BUFF_ONREM
+}
+
+MUTATOR_HOOKFUNCTION(buffs, SpectateCopy)
+{
+       entity spectatee = M_ARGV(0, entity);
+       entity client = M_ARGV(1, entity);
+
+       client.buffs = spectatee.buffs;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, VehicleEnter)
+{
+       entity player = M_ARGV(0, entity);
+       entity veh = M_ARGV(1, entity);
+
+       veh.buffs = player.buffs;
+       player.buffs = 0;
+       veh.buff_time = max(0, player.buff_time - time);
+       player.buff_time = 0;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, VehicleExit)
+{
+       entity player = M_ARGV(0, entity);
+       entity veh = M_ARGV(1, entity);
+
+       player.buffs = player.oldbuffs = veh.buffs;
+       veh.buffs = 0;
+       player.buff_time = time + veh.buff_time;
+       veh.buff_time = 0;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerRegen)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.buffs & BUFF_MEDIC.m_itemid)
+       {
+               M_ARGV(2, float) = autocvar_g_buffs_medic_rot; // rot_mod
+               M_ARGV(4, float) = M_ARGV(1, float) = autocvar_g_buffs_medic_max; // limit_mod = max_mod
+               M_ARGV(2, float) = autocvar_g_buffs_medic_regen; // regen_mod
+       }
+
+       if(player.buffs & BUFF_SPEED.m_itemid)
+               M_ARGV(2, float) = autocvar_g_buffs_speed_regen; // regen_mod
+}
+
+REPLICATE(cvar_cl_buffs_autoreplace, bool, "cl_buffs_autoreplace");
+
+MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":Buffs");
+}
+
+MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Buffs");
+}
+
+void buffs_DelayedInit(entity this)
+{
+       if(autocvar_g_buffs_spawn_count > 0)
+       if(find(NULL, classname, "item_buff") == NULL)
+       {
+               float i;
+               for(i = 0; i < autocvar_g_buffs_spawn_count; ++i)
+               {
+                       entity e = spawn();
+                       e.spawnflags |= 64; // always randomize
+                       e.velocity = randomvec() * 250; // this gets reset anyway if random location works
+                       buff_Init(e);
+               }
+       }
+}
diff --git a/qcsrc/common/mutators/mutator/buffs/sv_buffs.qh b/qcsrc/common/mutators/mutator/buffs/sv_buffs.qh
new file mode 100644 (file)
index 0000000..b9fc1e4
--- /dev/null
@@ -0,0 +1,77 @@
+#pragma once
+
+#include "buffs.qh"
+
+#include "../instagib/_mod.qh"
+
+bool  autocvar_g_buffs_effects;
+float autocvar_g_buffs_waypoint_distance;
+bool autocvar_g_buffs_randomize;
+float autocvar_g_buffs_random_lifetime;
+bool autocvar_g_buffs_random_location;
+int autocvar_g_buffs_random_location_attempts;
+int autocvar_g_buffs_spawn_count;
+bool autocvar_g_buffs_replace_powerups;
+float autocvar_g_buffs_cooldown_activate;
+float autocvar_g_buffs_cooldown_respawn;
+float autocvar_g_buffs_resistance_blockpercent;
+float autocvar_g_buffs_medic_survive_chance;
+float autocvar_g_buffs_medic_survive_health;
+float autocvar_g_buffs_medic_rot;
+float autocvar_g_buffs_medic_max;
+float autocvar_g_buffs_medic_regen;
+float autocvar_g_buffs_medic_heal_amount = 15;
+float autocvar_g_buffs_medic_heal_delay = 1;
+float autocvar_g_buffs_medic_heal_range = 400;
+float autocvar_g_buffs_vengeance_damage_multiplier;
+float autocvar_g_buffs_bash_force;
+float autocvar_g_buffs_bash_force_self;
+float autocvar_g_buffs_disability_slowtime;
+float autocvar_g_buffs_disability_speed;
+float autocvar_g_buffs_disability_rate;
+float autocvar_g_buffs_disability_weaponspeed;
+float autocvar_g_buffs_speed_speed;
+float autocvar_g_buffs_speed_rate;
+float autocvar_g_buffs_speed_weaponspeed;
+float autocvar_g_buffs_speed_damage_take;
+float autocvar_g_buffs_speed_regen;
+float autocvar_g_buffs_vampire_damage_steal;
+float autocvar_g_buffs_invisible_alpha;
+float autocvar_g_buffs_jump_height;
+float autocvar_g_buffs_inferno_burntime_factor;
+float autocvar_g_buffs_inferno_burntime_min_time;
+float autocvar_g_buffs_inferno_burntime_target_damage;
+float autocvar_g_buffs_inferno_burntime_target_time;
+float autocvar_g_buffs_inferno_damagemultiplier;
+float autocvar_g_buffs_swapper_range;
+float autocvar_g_buffs_magnet_range_item;
+float autocvar_g_buffs_magnet_range_buff = 200;
+float autocvar_g_buffs_luck_chance = 0.15;
+float autocvar_g_buffs_luck_damagemultiplier = 3;
+
+// ammo
+.float buff_ammo_prev_infitems;
+.int buff_ammo_prev_clipload;
+// invisible
+.float buff_invisible_prev_alpha;
+// medic
+.float buff_medic_healtime;
+// disability
+.float buff_disability_time;
+.float buff_disability_effect_time;
+// common buff variables
+.float buff_effect_delay;
+
+// buff definitions
+.float buff_active;
+.float buff_activetime;
+.float buff_activetime_updated;
+.entity buff_waypoint;
+.int oldbuffs; // for updating effects
+.entity buff_model; // controls effects (TODO: make csqc)
+
+const vector BUFF_MIN = ('-16 -16 -20');
+const vector BUFF_MAX = ('16 16 20');
+
+// client side options
+.float cvar_cl_buffs_autoreplace;
index f636696e64fc2506cedd588e63afc99a5a31d80d..a67e9455d9233640030bd1e0b879ff7b980ee0e8 100644 (file)
@@ -1,4 +1,7 @@
-#ifdef IMPLEMENTATION
+#include "bugrigs.qh"
+
+#ifdef GAMEQC
+
 #ifdef SVQC
        #include <server/antilag.qh>
 #endif
@@ -311,4 +314,5 @@ MUTATOR_HOOKFUNCTION(bugrigs, BuildMutatorsPrettyString)
 }
 
 #endif
+
 #endif
diff --git a/qcsrc/common/mutators/mutator/bugrigs/bugrigs.qh b/qcsrc/common/mutators/mutator/bugrigs/bugrigs.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mutators/mutator/bugrigs/module.inc b/qcsrc/common/mutators/mutator/bugrigs/module.inc
deleted file mode 100644 (file)
index cef744f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifndef MENUQC
-#include "bugrigs.qc"
-#endif
index 3ddb376fc9db5f685cc219bf52ecd0332b37f5c6..07c2ae2722fda8db1ff7c0d6aa088d71edeb1192 100644 (file)
@@ -1,2 +1,5 @@
 // generated file; do not modify
 #include <common/mutators/mutator/campcheck/campcheck.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/campcheck/sv_campcheck.qc>
+#endif
index 81345f1cff98c0a79d02e339007a63ff5550a1d8..c52811129b200a6b14867af6d9bca7fc01d3c38a 100644 (file)
@@ -1,2 +1,5 @@
 // generated file; do not modify
 #include <common/mutators/mutator/campcheck/campcheck.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/campcheck/sv_campcheck.qh>
+#endif
index 8be3215498f3ce7a34245121e616edff2af73a03..822d4af7808ea0757d4c3dd67bab12f520fcb681 100644 (file)
@@ -1,92 +1 @@
-#ifdef IMPLEMENTATION
-float autocvar_g_campcheck_damage;
-float autocvar_g_campcheck_distance;
-float autocvar_g_campcheck_interval;
-
-REGISTER_MUTATOR(campcheck, cvar("g_campcheck"));
-
-.float campcheck_nextcheck;
-.float campcheck_traveled_distance;
-
-MUTATOR_HOOKFUNCTION(campcheck, PlayerDies)
-{
-       entity frag_target = M_ARGV(2, entity);
-
-       Kill_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CPID_CAMPCHECK);
-}
-
-MUTATOR_HOOKFUNCTION(campcheck, PlayerDamage_Calculate)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-
-       if(IS_PLAYER(frag_target))
-       if(IS_PLAYER(frag_attacker))
-       if(frag_attacker != frag_target)
-       {
-               frag_target.campcheck_traveled_distance = autocvar_g_campcheck_distance;
-               frag_attacker.campcheck_traveled_distance = autocvar_g_campcheck_distance;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(campcheck, PlayerPreThink)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(!gameover)
-       if(!warmup_stage) // don't consider it camping during warmup?
-       if(time >= game_starttime)
-       if(IS_PLAYER(player))
-       if(IS_REAL_CLIENT(player)) // bots may camp, but that's no reason to constantly kill them
-       if(!IS_DEAD(player))
-       if(!forbidWeaponUse(player))
-       if(!STAT(FROZEN, player))
-       if(!PHYS_INPUT_BUTTON_CHAT(player))
-       if(autocvar_g_campcheck_interval)
-       {
-               vector dist;
-
-               // calculate player movement (in 2 dimensions only, so jumping on one spot doesn't count as movement)
-               dist = player.prevorigin - player.origin;
-               dist.z = 0;
-               player.campcheck_traveled_distance += fabs(vlen(dist));
-
-               if((autocvar_g_campaign && !campaign_bots_may_start) || (time < game_starttime) || (round_handler_IsActive() && !round_handler_IsRoundStarted()))
-               {
-                       player.campcheck_nextcheck = time + autocvar_g_campcheck_interval * 2;
-                       player.campcheck_traveled_distance = 0;
-               }
-
-               if(time > player.campcheck_nextcheck)
-               {
-                       if(player.campcheck_traveled_distance < autocvar_g_campcheck_distance)
-                       {
-                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CAMPCHECK);
-                               if(player.vehicle)
-                                       Damage(player.vehicle, NULL, NULL, autocvar_g_campcheck_damage * 2, DEATH_CAMP.m_id, player.vehicle.origin, '0 0 0');
-                               else
-                                       Damage(player, NULL, NULL, bound(0, autocvar_g_campcheck_damage, player.health + player.armorvalue * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP.m_id, player.origin, '0 0 0');
-                       }
-                       player.campcheck_nextcheck = time + autocvar_g_campcheck_interval;
-                       player.campcheck_traveled_distance = 0;
-               }
-
-               return;
-       }
-
-       player.campcheck_nextcheck = time + autocvar_g_campcheck_interval; // one of the above checks failed, so keep the timer up to date
-}
-
-MUTATOR_HOOKFUNCTION(campcheck, PlayerSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       player.campcheck_nextcheck = time + autocvar_g_campcheck_interval * 2;
-       player.campcheck_traveled_distance = 0;
-}
-
-MUTATOR_HOOKFUNCTION(campcheck, BuildMutatorsString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":CampCheck");
-}
-#endif
+#include "campcheck.qh"
diff --git a/qcsrc/common/mutators/mutator/campcheck/campcheck.qh b/qcsrc/common/mutators/mutator/campcheck/campcheck.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mutators/mutator/campcheck/module.inc b/qcsrc/common/mutators/mutator/campcheck/module.inc
deleted file mode 100644 (file)
index 9f4181f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "campcheck.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/campcheck/sv_campcheck.qc b/qcsrc/common/mutators/mutator/campcheck/sv_campcheck.qc
new file mode 100644 (file)
index 0000000..c4d2e03
--- /dev/null
@@ -0,0 +1,92 @@
+#include "sv_campcheck.qh"
+
+float autocvar_g_campcheck_damage;
+float autocvar_g_campcheck_distance;
+float autocvar_g_campcheck_interval;
+
+REGISTER_MUTATOR(campcheck, cvar("g_campcheck"));
+
+.float campcheck_nextcheck;
+.float campcheck_traveled_distance;
+
+MUTATOR_HOOKFUNCTION(campcheck, PlayerDies)
+{
+       entity frag_target = M_ARGV(2, entity);
+
+       Kill_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CPID_CAMPCHECK);
+}
+
+MUTATOR_HOOKFUNCTION(campcheck, PlayerDamage_Calculate)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+
+       if(IS_PLAYER(frag_target))
+       if(IS_PLAYER(frag_attacker))
+       if(frag_attacker != frag_target)
+       {
+               frag_target.campcheck_traveled_distance = autocvar_g_campcheck_distance;
+               frag_attacker.campcheck_traveled_distance = autocvar_g_campcheck_distance;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(campcheck, PlayerPreThink)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(!gameover)
+       if(!warmup_stage) // don't consider it camping during warmup?
+       if(time >= game_starttime)
+       if(IS_PLAYER(player))
+       if(IS_REAL_CLIENT(player)) // bots may camp, but that's no reason to constantly kill them
+       if(!IS_DEAD(player))
+       if(!forbidWeaponUse(player))
+       if(!STAT(FROZEN, player))
+       if(!PHYS_INPUT_BUTTON_CHAT(player))
+       if(autocvar_g_campcheck_interval)
+       {
+               vector dist;
+
+               // calculate player movement (in 2 dimensions only, so jumping on one spot doesn't count as movement)
+               dist = player.prevorigin - player.origin;
+               dist.z = 0;
+               player.campcheck_traveled_distance += fabs(vlen(dist));
+
+               if((autocvar_g_campaign && !campaign_bots_may_start) || (time < game_starttime) || (round_handler_IsActive() && !round_handler_IsRoundStarted()))
+               {
+                       player.campcheck_nextcheck = time + autocvar_g_campcheck_interval * 2;
+                       player.campcheck_traveled_distance = 0;
+               }
+
+               if(time > player.campcheck_nextcheck)
+               {
+                       if(player.campcheck_traveled_distance < autocvar_g_campcheck_distance)
+                       {
+                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CAMPCHECK);
+                               if(player.vehicle)
+                                       Damage(player.vehicle, NULL, NULL, autocvar_g_campcheck_damage * 2, DEATH_CAMP.m_id, player.vehicle.origin, '0 0 0');
+                               else
+                                       Damage(player, NULL, NULL, bound(0, autocvar_g_campcheck_damage, player.health + player.armorvalue * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP.m_id, player.origin, '0 0 0');
+                       }
+                       player.campcheck_nextcheck = time + autocvar_g_campcheck_interval;
+                       player.campcheck_traveled_distance = 0;
+               }
+
+               return;
+       }
+
+       player.campcheck_nextcheck = time + autocvar_g_campcheck_interval; // one of the above checks failed, so keep the timer up to date
+}
+
+MUTATOR_HOOKFUNCTION(campcheck, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       player.campcheck_nextcheck = time + autocvar_g_campcheck_interval * 2;
+       player.campcheck_traveled_distance = 0;
+}
+
+MUTATOR_HOOKFUNCTION(campcheck, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":CampCheck");
+}
diff --git a/qcsrc/common/mutators/mutator/campcheck/sv_campcheck.qh b/qcsrc/common/mutators/mutator/campcheck/sv_campcheck.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 72136952258113fec67b40cba93287bfc3b3a6a5..34fdea74797b23989b222c2b98ae907873338b80 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/cloaked/cloaked.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/cloaked/sv_cloaked.qc>
+#endif
index 5606b9aafd5edb118d1d44713cdd8dcaee399a3f..b225a2be5b0757d6bfe5e4f43f2e0022567c64f5 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/cloaked/cloaked.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/cloaked/sv_cloaked.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/cloaked/cloaked.qc b/qcsrc/common/mutators/mutator/cloaked/cloaked.qc
deleted file mode 100644 (file)
index 4fca532..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifdef IMPLEMENTATION
-
-REGISTER_MUTATOR(cloaked, cvar("g_cloaked"));
-
-float autocvar_g_balance_cloaked_alpha;
-
-MUTATOR_HOOKFUNCTION(cloaked, SetDefaultAlpha)
-{
-    default_player_alpha = autocvar_g_balance_cloaked_alpha;
-    default_weapon_alpha = default_player_alpha;
-    return true;
-}
-
-MUTATOR_HOOKFUNCTION(cloaked, BuildMutatorsPrettyString)
-{
-       if (!g_cts) M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Cloaked");
-}
-
-#endif
diff --git a/qcsrc/common/mutators/mutator/cloaked/module.inc b/qcsrc/common/mutators/mutator/cloaked/module.inc
deleted file mode 100644 (file)
index 3d3a042..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "cloaked.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/cloaked/sv_cloaked.qc b/qcsrc/common/mutators/mutator/cloaked/sv_cloaked.qc
new file mode 100644 (file)
index 0000000..eb45d4b
--- /dev/null
@@ -0,0 +1,17 @@
+#include "sv_cloaked.qh"
+
+REGISTER_MUTATOR(cloaked, cvar("g_cloaked"));
+
+float autocvar_g_balance_cloaked_alpha;
+
+MUTATOR_HOOKFUNCTION(cloaked, SetDefaultAlpha)
+{
+    default_player_alpha = autocvar_g_balance_cloaked_alpha;
+    default_weapon_alpha = default_player_alpha;
+    return true;
+}
+
+MUTATOR_HOOKFUNCTION(cloaked, BuildMutatorsPrettyString)
+{
+       if (!g_cts) M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Cloaked");
+}
diff --git a/qcsrc/common/mutators/mutator/cloaked/sv_cloaked.qh b/qcsrc/common/mutators/mutator/cloaked/sv_cloaked.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 878a854fb79ccc27bcbe6ffdd7c1fe7a7900a76e..88af5496b3f17fba8f7dfa57d226616ce6d1a95f 100644 (file)
@@ -1,13 +1,5 @@
-#ifndef MUTATOR_DAMAGETEXT_H
-#define MUTATOR_DAMAGETEXT_H
+#include "damagetext.qh"
 
-#ifdef MENUQC
-#include <menu/xonotic/tab.qh>
-#endif
-
-#endif
-
-#ifdef IMPLEMENTATION
 REGISTER_MUTATOR(damagetext, true);
 
 #if defined(CSQC) || defined(MENUQC)
@@ -157,8 +149,10 @@ NET_HANDLE(damagetext, bool isNew)
 #endif
 
 #ifdef MENUQC
+
+#include <menu/gamesettings.qh>
+
 CLASS(XonoticDamageTextSettings, XonoticTab)
-    #include <menu/gamesettings.qh>
     REGISTER_SETTINGS(damagetext, NEW(XonoticDamageTextSettings));
     ATTRIB(XonoticDamageTextSettings, title, string, _("Damage text"));
     ATTRIB(XonoticDamageTextSettings, intendedWidth, float, 0.9);
@@ -193,7 +187,6 @@ CLASS(XonoticDamageTextSettings, XonoticTab)
                 setDependent(e, "cl_damagetext", 1, 1);
         this.TR(this);
         this.TR(this);
-        // friendly fire
             this.TD(this, 1, 3, e = makeXonoticCheckBox(0, "cl_damagetext_friendlyfire", _("Draw damage numbers for friendly fire")));
                 setDependent(e, "cl_damagetext", 1, 1);
         this.TR(this);
@@ -205,4 +198,3 @@ CLASS(XonoticDamageTextSettings, XonoticTab)
     }
 ENDCLASS(XonoticDamageTextSettings)
 #endif
-#endif
diff --git a/qcsrc/common/mutators/mutator/damagetext/damagetext.qh b/qcsrc/common/mutators/mutator/damagetext/damagetext.qh
new file mode 100644 (file)
index 0000000..7228f37
--- /dev/null
@@ -0,0 +1,5 @@
+#pragma once
+
+#ifdef MENUQC
+#include <menu/xonotic/tab.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/damagetext/module.inc b/qcsrc/common/mutators/mutator/damagetext/module.inc
deleted file mode 100644 (file)
index 8e70be7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include "damagetext.qc"
index 4902d5fc1b36e0f34f3be37ebde5418e55306575..80a7828a703f409a707d36aac3b0e59fc8f02831 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/dodging/dodging.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/dodging/sv_dodging.qc>
+#endif
index b2b65f02f7afefee6e820ad90d2a3c7cf6b65cb7..fef7b8e6e4e7f289ea505ba469708bc116e3a280 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/dodging/dodging.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/dodging/sv_dodging.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/dodging/dodging.qc b/qcsrc/common/mutators/mutator/dodging/dodging.qc
deleted file mode 100644 (file)
index 7ddfcea..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-#ifdef IMPLEMENTATION
-
-#define PHYS_DODGING                                           STAT(DODGING, this)
-#define PHYS_DODGING_DELAY                                     STAT(DODGING_DELAY, this)
-#define PHYS_DODGING_DISTANCE_THRESHOLD        STAT(DODGING_DISTANCE_THRESHOLD, this)
-#define PHYS_DODGING_FROZEN_NODOUBLETAP                STAT(DODGING_FROZEN_NO_DOUBLETAP, this)
-#define PHYS_DODGING_HEIGHT_THRESHOLD          STAT(DODGING_HEIGHT_THRESHOLD, this)
-#define PHYS_DODGING_HORIZ_SPEED                       STAT(DODGING_HORIZ_SPEED, this)
-#define PHYS_DODGING_HORIZ_SPEED_FROZEN        STAT(DODGING_HORIZ_SPEED_FROZEN, this)
-#define PHYS_DODGING_RAMP_TIME                                 STAT(DODGING_RAMP_TIME, this)
-#define PHYS_DODGING_UP_SPEED                          STAT(DODGING_UP_SPEED, this)
-#define PHYS_DODGING_WALL                                      STAT(DODGING_WALL, this)
-#define PHYS_DODGING_AIR                                       STAT(DODGING_AIR, this)
-#define PHYS_DODGING_PRESSED_KEYS(s)           (s).pressedkeys
-
-#ifdef CSQC
-       #define PHYS_DODGING_FRAMETIME                          (1 / (frametime <= 0 ? 60 : frametime))
-       #define PHYS_DODGING_TIMEOUT(s)                         STAT(DODGING_TIMEOUT)
-#elif defined(SVQC)
-       #define PHYS_DODGING_FRAMETIME                          sys_frametime
-       #define PHYS_DODGING_TIMEOUT(s)                         s.cvar_cl_dodging_timeout
-#endif
-
-#ifdef SVQC
-
-bool autocvar_sv_dodging_sound;
-
-// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
-.float dodging_action;
-
-// the jump part of the dodge cannot be ramped
-.float dodging_single_action;
-
-#include <common/animdecide.qh>
-#include <common/physics/player.qh>
-
-.float cvar_cl_dodging_timeout = _STAT(DODGING_TIMEOUT);
-
-REGISTER_MUTATOR(dodging, cvar("g_dodging"))
-{
-       // this just turns on the cvar.
-       MUTATOR_ONADD
-       {
-               g_dodging = cvar("g_dodging");
-       }
-
-       // this just turns off the cvar.
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               g_dodging = 0;
-       }
-
-       return false;
-}
-
-#elif defined(CSQC)
-REGISTER_MUTATOR(dodging, true);
-#endif
-
-// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
-.float dodging_action;
-
-// the jump part of the dodge cannot be ramped
-.float dodging_single_action;
-
-
-// these are used to store the last key press time for each of the keys..
-.float last_FORWARD_KEY_time;
-.float last_BACKWARD_KEY_time;
-.float last_LEFT_KEY_time;
-.float last_RIGHT_KEY_time;
-
-// these store the movement direction at the time of the dodge action happening.
-.vector dodging_direction;
-
-// this indicates the last time a dodge was executed. used to check if another one is allowed
-// and to ramp up the dodge acceleration in the physics hook.
-.float last_dodging_time;
-
-// This is the velocity gain to be added over the ramp time.
-// It will decrease from frame to frame during dodging_action = 1
-// until it's 0.
-.float dodging_velocity_gain;
-
-#ifdef CSQC
-.int pressedkeys;
-#endif
-
-// returns 1 if the player is close to a wall
-bool check_close_to_wall(entity this, float threshold)
-{
-       if (PHYS_DODGING_WALL == 0) { return false; }
-
-#define X(OFFSET) \
-       tracebox(this.origin, this.mins, this.maxs, this.origin + OFFSET, true, this); \
-       if(trace_fraction < 1 && vdist(this.origin - trace_endpos, <, threshold)) \
-               return true;
-       X(1000*v_right);
-       X(-1000*v_right);
-       X(1000*v_forward);
-       X(-1000*v_forward);
-#undef X
-
-       return false;
-}
-
-bool check_close_to_ground(entity this, float threshold)
-{
-       return IS_ONGROUND(this) ? true : false;
-}
-
-float PM_dodging_checkpressedkeys(entity this)
-{
-       if(!PHYS_DODGING)
-               return false;
-
-       float frozen_dodging = (PHYS_FROZEN(this) && PHYS_DODGING_FROZEN(this));
-       float frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_NODOUBLETAP);
-
-       // first check if the last dodge is far enough back in time so we can dodge again
-       if ((time - this.last_dodging_time) < PHYS_DODGING_DELAY)
-               return false;
-
-       makevectors(this.angles);
-
-       if(!PHYS_DODGING_AIR)
-       if (check_close_to_ground(this, PHYS_DODGING_HEIGHT_THRESHOLD) != 1
-               && check_close_to_wall(this, PHYS_DODGING_DISTANCE_THRESHOLD) != 1)
-               return true;
-
-       float tap_direction_x = 0;
-       float tap_direction_y = 0;
-       bool dodge_detected = false;
-
-       #define X(COND,BTN,RESULT)                                                                                                                      \
-       if (this.movement_##COND)                                                                                               \
-               /* is this a state change? */                                                                                                   \
-               if(!(PHYS_DODGING_PRESSED_KEYS(this) & KEY_##BTN) || frozen_no_doubletap) {             \
-                               tap_direction_##RESULT;                                                                                                 \
-                               if ((time - this.last_##BTN##_KEY_time) < PHYS_DODGING_TIMEOUT(this) || frozen_no_doubletap)    \
-                                       dodge_detected = true;                                                                                                  \
-                               this.last_##BTN##_KEY_time = time;                                                                              \
-               }
-       X(x < 0, BACKWARD,      x--);
-       X(x > 0, FORWARD,       x++);
-       X(y < 0, LEFT,          y--);
-       X(y > 0, RIGHT,         y++);
-       #undef X
-
-       if (dodge_detected)
-       {
-               this.last_dodging_time = time;
-
-               this.dodging_action = 1;
-               this.dodging_single_action = 1;
-
-               this.dodging_velocity_gain = PHYS_DODGING_HORIZ_SPEED;
-
-               this.dodging_direction_x = tap_direction_x;
-               this.dodging_direction_y = tap_direction_y;
-
-               // normalize the dodging_direction vector.. (unlike UT99) XD
-               float length = this.dodging_direction_x * this.dodging_direction_x
-                                       + this.dodging_direction_y * this.dodging_direction_y;
-               length = sqrt(length);
-
-               this.dodging_direction_x = this.dodging_direction_x * 1.0 / length;
-               this.dodging_direction_y = this.dodging_direction_y * 1.0 / length;
-               return true;
-       }
-       return false;
-}
-
-void PM_dodging(entity this)
-{
-       if (!PHYS_DODGING)
-               return;
-
-    if (IS_DEAD(this))
-        return;
-
-       // when swimming, no dodging allowed..
-       if (this.waterlevel >= WATERLEVEL_SWIMMING)
-       {
-               this.dodging_action = 0;
-               this.dodging_direction_x = 0;
-               this.dodging_direction_y = 0;
-               return;
-       }
-
-       // make sure v_up, v_right and v_forward are sane
-       if(PHYS_DODGING_AIR)
-               makevectors(this.v_angle);
-       else
-               makevectors(this.angles);
-
-       // if we have e.g. 0.5 sec ramptime and a frametime of 0.25, then the ramp code
-       // will be called ramp_time/frametime times = 2 times. so, we need to
-       // add 0.5 * the total speed each frame until the dodge action is done..
-       float common_factor = PHYS_DODGING_FRAMETIME / PHYS_DODGING_RAMP_TIME;
-
-       // if ramp time is smaller than frametime we get problems ;D
-       common_factor = min(common_factor, 1);
-
-       float horiz_speed = PHYS_FROZEN(this) ? PHYS_DODGING_HORIZ_SPEED_FROZEN : PHYS_DODGING_HORIZ_SPEED;
-       float new_velocity_gain = this.dodging_velocity_gain - (common_factor * horiz_speed);
-       new_velocity_gain = max(0, new_velocity_gain);
-
-       float velocity_difference = this.dodging_velocity_gain - new_velocity_gain;
-
-       // ramp up dodging speed by adding some velocity each frame.. TODO: do it! :D
-       if (this.dodging_action == 1)
-       {
-               //disable jump key during dodge accel phase
-               if(this.movement_z > 0) { this.movement_z = 0; }
-
-               this.velocity += ((this.dodging_direction_y * velocity_difference) * v_right)
-                                       + ((this.dodging_direction_x * velocity_difference) * v_forward);
-
-               this.dodging_velocity_gain = this.dodging_velocity_gain - velocity_difference;
-       }
-
-       // the up part of the dodge is a single shot action
-       if (this.dodging_single_action == 1)
-       {
-               UNSET_ONGROUND(this);
-
-               this.velocity += PHYS_DODGING_UP_SPEED * v_up;
-
-#ifdef SVQC
-               if (autocvar_sv_dodging_sound)
-                       PlayerSound(this, playersound_jump, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND);
-
-               animdecide_setaction(this, ANIMACTION_JUMP, true);
-#endif
-
-               this.dodging_single_action = 0;
-       }
-
-       // are we done with the dodging ramp yet?
-       if((this.dodging_action == 1) && ((time - this.last_dodging_time) > PHYS_DODGING_RAMP_TIME))
-       {
-               // reset state so next dodge can be done correctly
-               this.dodging_action = 0;
-               this.dodging_direction_x = 0;
-               this.dodging_direction_y = 0;
-       }
-}
-
-void PM_dodging_GetPressedKeys(entity this)
-{
-#ifdef CSQC
-       if(!PHYS_DODGING) { return; }
-
-       PM_dodging_checkpressedkeys(this);
-
-       int keys = this.pressedkeys;
-       keys = BITSET(keys, KEY_FORWARD,        this.movement.x > 0);
-       keys = BITSET(keys, KEY_BACKWARD,       this.movement.x < 0);
-       keys = BITSET(keys, KEY_RIGHT,          this.movement.y > 0);
-       keys = BITSET(keys, KEY_LEFT,           this.movement.y < 0);
-
-       keys = BITSET(keys, KEY_JUMP,           PHYS_INPUT_BUTTON_JUMP(this));
-       keys = BITSET(keys, KEY_CROUCH,         PHYS_INPUT_BUTTON_CROUCH(this));
-       keys = BITSET(keys, KEY_ATCK,           PHYS_INPUT_BUTTON_ATCK(this));
-       keys = BITSET(keys, KEY_ATCK2,          PHYS_INPUT_BUTTON_ATCK2(this));
-       this.pressedkeys = keys;
-#endif
-}
-
-MUTATOR_HOOKFUNCTION(dodging, PlayerPhysics)
-{
-    entity player = M_ARGV(0, entity);
-
-       // print("dodging_PlayerPhysics\n");
-       PM_dodging_GetPressedKeys(player);
-       PM_dodging(player);
-}
-
-#ifdef SVQC
-
-REPLICATE(cvar_cl_dodging_timeout, float, "cl_dodging_timeout");
-
-MUTATOR_HOOKFUNCTION(dodging, GetPressedKeys)
-{
-       entity player = M_ARGV(0, entity);
-
-       PM_dodging_checkpressedkeys(player);
-}
-
-#endif
-#endif
diff --git a/qcsrc/common/mutators/mutator/dodging/module.inc b/qcsrc/common/mutators/mutator/dodging/module.inc
deleted file mode 100644 (file)
index 60b193f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-       #include "dodging.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/dodging/sv_dodging.qc b/qcsrc/common/mutators/mutator/dodging/sv_dodging.qc
new file mode 100644 (file)
index 0000000..f9cee61
--- /dev/null
@@ -0,0 +1,291 @@
+#include "sv_dodging.qh"
+
+#define PHYS_DODGING                                           STAT(DODGING, this)
+#define PHYS_DODGING_DELAY                                     STAT(DODGING_DELAY, this)
+#define PHYS_DODGING_DISTANCE_THRESHOLD        STAT(DODGING_DISTANCE_THRESHOLD, this)
+#define PHYS_DODGING_FROZEN_NODOUBLETAP                STAT(DODGING_FROZEN_NO_DOUBLETAP, this)
+#define PHYS_DODGING_HEIGHT_THRESHOLD          STAT(DODGING_HEIGHT_THRESHOLD, this)
+#define PHYS_DODGING_HORIZ_SPEED                       STAT(DODGING_HORIZ_SPEED, this)
+#define PHYS_DODGING_HORIZ_SPEED_FROZEN        STAT(DODGING_HORIZ_SPEED_FROZEN, this)
+#define PHYS_DODGING_RAMP_TIME                                 STAT(DODGING_RAMP_TIME, this)
+#define PHYS_DODGING_UP_SPEED                          STAT(DODGING_UP_SPEED, this)
+#define PHYS_DODGING_WALL                                      STAT(DODGING_WALL, this)
+#define PHYS_DODGING_AIR                                       STAT(DODGING_AIR, this)
+#define PHYS_DODGING_PRESSED_KEYS(s)           (s).pressedkeys
+
+#ifdef CSQC
+       #define PHYS_DODGING_FRAMETIME                          (1 / (frametime <= 0 ? 60 : frametime))
+       #define PHYS_DODGING_TIMEOUT(s)                         STAT(DODGING_TIMEOUT)
+#elif defined(SVQC)
+       #define PHYS_DODGING_FRAMETIME                          sys_frametime
+       #define PHYS_DODGING_TIMEOUT(s)                         s.cvar_cl_dodging_timeout
+#endif
+
+#ifdef SVQC
+
+bool autocvar_sv_dodging_sound;
+
+// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
+.float dodging_action;
+
+// the jump part of the dodge cannot be ramped
+.float dodging_single_action;
+
+#include <common/animdecide.qh>
+#include <common/physics/player.qh>
+
+.float cvar_cl_dodging_timeout = _STAT(DODGING_TIMEOUT);
+
+REGISTER_MUTATOR(dodging, cvar("g_dodging"))
+{
+       // this just turns on the cvar.
+       MUTATOR_ONADD
+       {
+               g_dodging = cvar("g_dodging");
+       }
+
+       // this just turns off the cvar.
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               g_dodging = 0;
+       }
+
+       return false;
+}
+
+#elif defined(CSQC)
+REGISTER_MUTATOR(dodging, true);
+#endif
+
+// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
+.float dodging_action;
+
+// the jump part of the dodge cannot be ramped
+.float dodging_single_action;
+
+
+// these are used to store the last key press time for each of the keys..
+.float last_FORWARD_KEY_time;
+.float last_BACKWARD_KEY_time;
+.float last_LEFT_KEY_time;
+.float last_RIGHT_KEY_time;
+
+// these store the movement direction at the time of the dodge action happening.
+.vector dodging_direction;
+
+// this indicates the last time a dodge was executed. used to check if another one is allowed
+// and to ramp up the dodge acceleration in the physics hook.
+.float last_dodging_time;
+
+// This is the velocity gain to be added over the ramp time.
+// It will decrease from frame to frame during dodging_action = 1
+// until it's 0.
+.float dodging_velocity_gain;
+
+#ifdef CSQC
+.int pressedkeys;
+#endif
+
+// returns 1 if the player is close to a wall
+bool check_close_to_wall(entity this, float threshold)
+{
+       if (PHYS_DODGING_WALL == 0) { return false; }
+
+#define X(OFFSET) \
+       tracebox(this.origin, this.mins, this.maxs, this.origin + OFFSET, true, this); \
+       if(trace_fraction < 1 && vdist(this.origin - trace_endpos, <, threshold)) \
+               return true;
+       X(1000*v_right);
+       X(-1000*v_right);
+       X(1000*v_forward);
+       X(-1000*v_forward);
+#undef X
+
+       return false;
+}
+
+bool check_close_to_ground(entity this, float threshold)
+{
+       return IS_ONGROUND(this) ? true : false;
+}
+
+float PM_dodging_checkpressedkeys(entity this)
+{
+       if(!PHYS_DODGING)
+               return false;
+
+       float frozen_dodging = (PHYS_FROZEN(this) && PHYS_DODGING_FROZEN(this));
+       float frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_NODOUBLETAP);
+
+       // first check if the last dodge is far enough back in time so we can dodge again
+       if ((time - this.last_dodging_time) < PHYS_DODGING_DELAY)
+               return false;
+
+       makevectors(this.angles);
+
+       if(!PHYS_DODGING_AIR)
+       if (check_close_to_ground(this, PHYS_DODGING_HEIGHT_THRESHOLD) != 1
+               && check_close_to_wall(this, PHYS_DODGING_DISTANCE_THRESHOLD) != 1)
+               return true;
+
+       float tap_direction_x = 0;
+       float tap_direction_y = 0;
+       bool dodge_detected = false;
+
+       #define X(COND,BTN,RESULT)                                                                                                                      \
+       if (this.movement_##COND)                                                                                               \
+               /* is this a state change? */                                                                                                   \
+               if(!(PHYS_DODGING_PRESSED_KEYS(this) & KEY_##BTN) || frozen_no_doubletap) {             \
+                               tap_direction_##RESULT;                                                                                                 \
+                               if ((time - this.last_##BTN##_KEY_time) < PHYS_DODGING_TIMEOUT(this) || frozen_no_doubletap)    \
+                                       dodge_detected = true;                                                                                                  \
+                               this.last_##BTN##_KEY_time = time;                                                                              \
+               }
+       X(x < 0, BACKWARD,      x--);
+       X(x > 0, FORWARD,       x++);
+       X(y < 0, LEFT,          y--);
+       X(y > 0, RIGHT,         y++);
+       #undef X
+
+       if (dodge_detected)
+       {
+               this.last_dodging_time = time;
+
+               this.dodging_action = 1;
+               this.dodging_single_action = 1;
+
+               this.dodging_velocity_gain = PHYS_DODGING_HORIZ_SPEED;
+
+               this.dodging_direction_x = tap_direction_x;
+               this.dodging_direction_y = tap_direction_y;
+
+               // normalize the dodging_direction vector.. (unlike UT99) XD
+               float length = this.dodging_direction_x * this.dodging_direction_x
+                                       + this.dodging_direction_y * this.dodging_direction_y;
+               length = sqrt(length);
+
+               this.dodging_direction_x = this.dodging_direction_x * 1.0 / length;
+               this.dodging_direction_y = this.dodging_direction_y * 1.0 / length;
+               return true;
+       }
+       return false;
+}
+
+void PM_dodging(entity this)
+{
+       if (!PHYS_DODGING)
+               return;
+
+    if (IS_DEAD(this))
+        return;
+
+       // when swimming, no dodging allowed..
+       if (this.waterlevel >= WATERLEVEL_SWIMMING)
+       {
+               this.dodging_action = 0;
+               this.dodging_direction_x = 0;
+               this.dodging_direction_y = 0;
+               return;
+       }
+
+       // make sure v_up, v_right and v_forward are sane
+       if(PHYS_DODGING_AIR)
+               makevectors(this.v_angle);
+       else
+               makevectors(this.angles);
+
+       // if we have e.g. 0.5 sec ramptime and a frametime of 0.25, then the ramp code
+       // will be called ramp_time/frametime times = 2 times. so, we need to
+       // add 0.5 * the total speed each frame until the dodge action is done..
+       float common_factor = PHYS_DODGING_FRAMETIME / PHYS_DODGING_RAMP_TIME;
+
+       // if ramp time is smaller than frametime we get problems ;D
+       common_factor = min(common_factor, 1);
+
+       float horiz_speed = PHYS_FROZEN(this) ? PHYS_DODGING_HORIZ_SPEED_FROZEN : PHYS_DODGING_HORIZ_SPEED;
+       float new_velocity_gain = this.dodging_velocity_gain - (common_factor * horiz_speed);
+       new_velocity_gain = max(0, new_velocity_gain);
+
+       float velocity_difference = this.dodging_velocity_gain - new_velocity_gain;
+
+       // ramp up dodging speed by adding some velocity each frame.. TODO: do it! :D
+       if (this.dodging_action == 1)
+       {
+               //disable jump key during dodge accel phase
+               if(this.movement_z > 0) { this.movement_z = 0; }
+
+               this.velocity += ((this.dodging_direction_y * velocity_difference) * v_right)
+                                       + ((this.dodging_direction_x * velocity_difference) * v_forward);
+
+               this.dodging_velocity_gain = this.dodging_velocity_gain - velocity_difference;
+       }
+
+       // the up part of the dodge is a single shot action
+       if (this.dodging_single_action == 1)
+       {
+               UNSET_ONGROUND(this);
+
+               this.velocity += PHYS_DODGING_UP_SPEED * v_up;
+
+#ifdef SVQC
+               if (autocvar_sv_dodging_sound)
+                       PlayerSound(this, playersound_jump, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND);
+
+               animdecide_setaction(this, ANIMACTION_JUMP, true);
+#endif
+
+               this.dodging_single_action = 0;
+       }
+
+       // are we done with the dodging ramp yet?
+       if((this.dodging_action == 1) && ((time - this.last_dodging_time) > PHYS_DODGING_RAMP_TIME))
+       {
+               // reset state so next dodge can be done correctly
+               this.dodging_action = 0;
+               this.dodging_direction_x = 0;
+               this.dodging_direction_y = 0;
+       }
+}
+
+void PM_dodging_GetPressedKeys(entity this)
+{
+#ifdef CSQC
+       if(!PHYS_DODGING) { return; }
+
+       PM_dodging_checkpressedkeys(this);
+
+       int keys = this.pressedkeys;
+       keys = BITSET(keys, KEY_FORWARD,        this.movement.x > 0);
+       keys = BITSET(keys, KEY_BACKWARD,       this.movement.x < 0);
+       keys = BITSET(keys, KEY_RIGHT,          this.movement.y > 0);
+       keys = BITSET(keys, KEY_LEFT,           this.movement.y < 0);
+
+       keys = BITSET(keys, KEY_JUMP,           PHYS_INPUT_BUTTON_JUMP(this));
+       keys = BITSET(keys, KEY_CROUCH,         PHYS_INPUT_BUTTON_CROUCH(this));
+       keys = BITSET(keys, KEY_ATCK,           PHYS_INPUT_BUTTON_ATCK(this));
+       keys = BITSET(keys, KEY_ATCK2,          PHYS_INPUT_BUTTON_ATCK2(this));
+       this.pressedkeys = keys;
+#endif
+}
+
+MUTATOR_HOOKFUNCTION(dodging, PlayerPhysics)
+{
+    entity player = M_ARGV(0, entity);
+
+       // print("dodging_PlayerPhysics\n");
+       PM_dodging_GetPressedKeys(player);
+       PM_dodging(player);
+}
+
+#ifdef SVQC
+
+REPLICATE(cvar_cl_dodging_timeout, float, "cl_dodging_timeout");
+
+MUTATOR_HOOKFUNCTION(dodging, GetPressedKeys)
+{
+       entity player = M_ARGV(0, entity);
+
+       PM_dodging_checkpressedkeys(player);
+}
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/dodging/sv_dodging.qh b/qcsrc/common/mutators/mutator/dodging/sv_dodging.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index d490ecaaff364d71ad3bc5511c5fb734a2f1cce2..cc60ccc1fd8a9bccf1a9006ca0b46a86796d35f8 100644 (file)
@@ -1,4 +1,6 @@
-#ifdef IMPLEMENTATION
+#include "doublejump.qh"
+
+#ifdef GAMEQC
 #ifdef SVQC
        #include <server/antilag.qh>
 #endif
@@ -31,5 +33,4 @@ MUTATOR_HOOKFUNCTION(doublejump, PlayerJump)
                }
        }
 }
-
 #endif
diff --git a/qcsrc/common/mutators/mutator/doublejump/doublejump.qh b/qcsrc/common/mutators/mutator/doublejump/doublejump.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mutators/mutator/doublejump/module.inc b/qcsrc/common/mutators/mutator/doublejump/module.inc
deleted file mode 100644 (file)
index f4c695b..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifndef MENUQC
-#include "doublejump.qc"
-#endif
index 006a5d5c7ee00abda6128a7f52b75bc16ba17ff7..2302d85fb1455148b9b37c612e601c59d941a093 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/globalforces/globalforces.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/globalforces/sv_globalforces.qc>
+#endif
index ac5cfd2442e5bb21c7a6384fc480c30b91912efb..c31ee5cfcb8ace1afa7157f7b38569db30cd8dbd 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/globalforces/globalforces.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/globalforces/sv_globalforces.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/globalforces/globalforces.qc b/qcsrc/common/mutators/mutator/globalforces/globalforces.qc
deleted file mode 100644 (file)
index 49ac468..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifdef IMPLEMENTATION
-
-AUTOCVAR(g_globalforces, float, false, "Global forces: knockback affects everyone");
-AUTOCVAR(g_globalforces_noself, bool, true, "Global forces: ignore self damage");
-AUTOCVAR(g_globalforces_self, float, 1, "Global forces: knockback self scale");
-AUTOCVAR(g_globalforces_range, float, 1000, "Global forces: max range of effect");
-REGISTER_MUTATOR(mutator_globalforces, autocvar_g_globalforces);
-
-MUTATOR_HOOKFUNCTION(mutator_globalforces, BuildMutatorsString) {
-    M_ARGV(0, string) = strcat(M_ARGV(0, string), ":GlobalForces");
-}
-
-MUTATOR_HOOKFUNCTION(mutator_globalforces, BuildMutatorsPrettyString) {
-    M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Global forces");
-}
-
-MUTATOR_HOOKFUNCTION(mutator_globalforces, PlayerDamage_SplitHealthArmor) {
-    entity frag_attacker = M_ARGV(1, entity);
-    entity frag_target = M_ARGV(2, entity);
-    if (autocvar_g_globalforces_noself && frag_target == frag_attacker) return;
-    vector damage_force = M_ARGV(3, vector) * autocvar_g_globalforces;
-    FOREACH_CLIENT(IS_PLAYER(it) && it != frag_target, {
-        if (autocvar_g_globalforces_range) {
-            if (vdist(it.origin - frag_target.origin, >, autocvar_g_globalforces_range)) {
-                continue;
-            }
-        }
-        float f = (it == frag_attacker) ? autocvar_g_globalforces_self : 1;
-        it.velocity += damage_explosion_calcpush(f * it.damageforcescale * damage_force, it.velocity, autocvar_g_balance_damagepush_speedfactor);
-    });
-}
-
-#endif
diff --git a/qcsrc/common/mutators/mutator/globalforces/module.inc b/qcsrc/common/mutators/mutator/globalforces/module.inc
deleted file mode 100644 (file)
index 2a0eec8..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-       #include "globalforces.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/globalforces/sv_globalforces.qc b/qcsrc/common/mutators/mutator/globalforces/sv_globalforces.qc
new file mode 100644 (file)
index 0000000..3e9cd0d
--- /dev/null
@@ -0,0 +1,31 @@
+#include "sv_globalforces.qh"
+
+AUTOCVAR(g_globalforces, float, false, "Global forces: knockback affects everyone");
+AUTOCVAR(g_globalforces_noself, bool, true, "Global forces: ignore self damage");
+AUTOCVAR(g_globalforces_self, float, 1, "Global forces: knockback self scale");
+AUTOCVAR(g_globalforces_range, float, 1000, "Global forces: max range of effect");
+REGISTER_MUTATOR(mutator_globalforces, autocvar_g_globalforces);
+
+MUTATOR_HOOKFUNCTION(mutator_globalforces, BuildMutatorsString) {
+    M_ARGV(0, string) = strcat(M_ARGV(0, string), ":GlobalForces");
+}
+
+MUTATOR_HOOKFUNCTION(mutator_globalforces, BuildMutatorsPrettyString) {
+    M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Global forces");
+}
+
+MUTATOR_HOOKFUNCTION(mutator_globalforces, PlayerDamage_SplitHealthArmor) {
+    entity frag_attacker = M_ARGV(1, entity);
+    entity frag_target = M_ARGV(2, entity);
+    if (autocvar_g_globalforces_noself && frag_target == frag_attacker) return;
+    vector damage_force = M_ARGV(3, vector) * autocvar_g_globalforces;
+    FOREACH_CLIENT(IS_PLAYER(it) && it != frag_target, {
+        if (autocvar_g_globalforces_range) {
+            if (vdist(it.origin - frag_target.origin, >, autocvar_g_globalforces_range)) {
+                continue;
+            }
+        }
+        float f = (it == frag_attacker) ? autocvar_g_globalforces_self : 1;
+        it.velocity += damage_explosion_calcpush(f * it.damageforcescale * damage_force, it.velocity, autocvar_g_balance_damagepush_speedfactor);
+    });
+}
diff --git a/qcsrc/common/mutators/mutator/globalforces/sv_globalforces.qh b/qcsrc/common/mutators/mutator/globalforces/sv_globalforces.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index ec6da662e7a1b26be37f1fe4cdd122874294448d..e5e68b6106fed48992f8d3d743eb9f087ac168c6 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/hook/hook.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/hook/sv_hook.qc>
+#endif
index 50c0c13726f6768634a7534eaeee654cf5f3bd8b..5a5d26e8172fd5ee077fc200e18a519b64acca0c 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/hook/hook.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/hook/sv_hook.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/hook/hook.qc b/qcsrc/common/mutators/mutator/hook/hook.qc
deleted file mode 100644 (file)
index e72134e..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifdef IMPLEMENTATION
-AUTOCVAR(g_grappling_hook, bool, false, _("let players spawn with the grappling hook which allows them to pull themselves up"));
-#ifdef SVQC
-REGISTER_MUTATOR(hook, autocvar_g_grappling_hook) {
-    MUTATOR_ONADD {
-        g_grappling_hook = true;
-        WEP_HOOK.ammo_factor = 0;
-    }
-    MUTATOR_ONROLLBACK_OR_REMOVE {
-        g_grappling_hook = false;
-        WEP_HOOK.ammo_factor = 1;
-    }
-
-    return false;
-}
-
-MUTATOR_HOOKFUNCTION(hook, BuildMutatorsString)
-{
-    M_ARGV(0, string) = strcat(M_ARGV(0, string), ":grappling_hook");
-}
-
-MUTATOR_HOOKFUNCTION(hook, BuildMutatorsPrettyString)
-{
-    M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Hook");
-}
-
-MUTATOR_HOOKFUNCTION(hook, BuildGameplayTipsString)
-{
-    M_ARGV(0, string) = strcat(M_ARGV(0, string), "\n\n^3grappling hook^8 is enabled, press 'e' to use it\n");
-}
-
-MUTATOR_HOOKFUNCTION(hook, PlayerSpawn)
-{
-    entity player = M_ARGV(0, entity);
-
-    player.offhand = OFFHAND_HOOK;
-}
-
-MUTATOR_HOOKFUNCTION(hook, FilterItem)
-{
-    entity item = M_ARGV(0, entity);
-
-    return item.weapon == WEP_HOOK.m_id;
-}
-
-#endif
-#endif
diff --git a/qcsrc/common/mutators/mutator/hook/module.inc b/qcsrc/common/mutators/mutator/hook/module.inc
deleted file mode 100644 (file)
index 61600c4..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "hook.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/hook/sv_hook.qc b/qcsrc/common/mutators/mutator/hook/sv_hook.qc
new file mode 100644 (file)
index 0000000..b5a196c
--- /dev/null
@@ -0,0 +1,47 @@
+#include "sv_hook.qh"
+
+AUTOCVAR(g_grappling_hook, bool, false, _("let players spawn with the grappling hook which allows them to pull themselves up"));
+#ifdef SVQC
+REGISTER_MUTATOR(hook, autocvar_g_grappling_hook) {
+    MUTATOR_ONADD {
+        g_grappling_hook = true;
+        WEP_HOOK.ammo_factor = 0;
+    }
+    MUTATOR_ONROLLBACK_OR_REMOVE {
+        g_grappling_hook = false;
+        WEP_HOOK.ammo_factor = 1;
+    }
+
+    return false;
+}
+
+MUTATOR_HOOKFUNCTION(hook, BuildMutatorsString)
+{
+    M_ARGV(0, string) = strcat(M_ARGV(0, string), ":grappling_hook");
+}
+
+MUTATOR_HOOKFUNCTION(hook, BuildMutatorsPrettyString)
+{
+    M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Hook");
+}
+
+MUTATOR_HOOKFUNCTION(hook, BuildGameplayTipsString)
+{
+    M_ARGV(0, string) = strcat(M_ARGV(0, string), "\n\n^3grappling hook^8 is enabled, press 'e' to use it\n");
+}
+
+MUTATOR_HOOKFUNCTION(hook, PlayerSpawn)
+{
+    entity player = M_ARGV(0, entity);
+
+    player.offhand = OFFHAND_HOOK;
+}
+
+MUTATOR_HOOKFUNCTION(hook, FilterItem)
+{
+    entity item = M_ARGV(0, entity);
+
+    return item.weapon == WEP_HOOK.m_id;
+}
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/hook/sv_hook.qh b/qcsrc/common/mutators/mutator/hook/sv_hook.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index dad005fe494a1002959c2ab5eafd094b4bd2ee6f..2195111f0f269e2903f767e3badf17644e0aa27d 100644 (file)
@@ -1,3 +1,5 @@
 // generated file; do not modify
-#include <common/mutators/mutator/instagib/instagib.qc>
 #include <common/mutators/mutator/instagib/items.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/instagib/sv_instagib.qc>
+#endif
index 2e88f427e9a143ec41187dd4a69f46cd8744cd0e..7097eaf390dac022c2840f7db4d9dc6ee7028368 100644 (file)
@@ -1,3 +1,5 @@
 // generated file; do not modify
-#include <common/mutators/mutator/instagib/instagib.qh>
 #include <common/mutators/mutator/instagib/items.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/instagib/sv_instagib.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/instagib/instagib.qc b/qcsrc/common/mutators/mutator/instagib/instagib.qc
deleted file mode 100644 (file)
index 25edbb2..0000000
+++ /dev/null
@@ -1,505 +0,0 @@
-#ifndef MUTATOR_INSTAGIB_H
-#define MUTATOR_INSTAGIB_H
-
-#include "items.qc"
-
-#ifdef SVQC
-float autocvar_g_instagib_invis_alpha;
-#endif
-
-#endif
-
-#ifdef IMPLEMENTATION
-#ifdef SVQC
-
-int autocvar_g_instagib_ammo_drop;
-int autocvar_g_instagib_extralives;
-float autocvar_g_instagib_speed_highspeed;
-
-#include <server/cl_client.qh>
-
-#include <common/items/all.qc>
-
-REGISTER_MUTATOR(mutator_instagib, cvar("g_instagib") && !g_nexball);
-
-spawnfunc(item_minst_cells)
-{
-       if (!g_instagib) { delete(this); return; }
-       if (!this.ammo_cells) this.ammo_cells = autocvar_g_instagib_ammo_drop;
-       StartItem(this, ITEM_VaporizerCells);
-}
-
-void instagib_invisibility(entity this)
-{
-       this.strength_finished = autocvar_g_balance_powerup_strength_time;
-       StartItem(this, ITEM_Invisibility);
-}
-
-void instagib_extralife(entity this)
-{
-       StartItem(this, ITEM_ExtraLife);
-}
-
-void instagib_speed(entity this)
-{
-       this.invincible_finished = autocvar_g_balance_powerup_invincible_time;
-       StartItem(this, ITEM_Speed);
-}
-
-.float instagib_nextthink;
-.float instagib_needammo;
-void instagib_stop_countdown(entity e)
-{
-       if (!e.instagib_needammo)
-               return;
-       Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER, CPID_INSTAGIB_FINDAMMO);
-       e.instagib_needammo = false;
-}
-void instagib_ammocheck(entity this)
-{
-       if(time < this.instagib_nextthink)
-               return;
-       if(!IS_PLAYER(this))
-               return; // not a player
-
-       if(IS_DEAD(this) || gameover)
-               instagib_stop_countdown(this);
-       else if (this.ammo_cells > 0 || (this.items & IT_UNLIMITED_WEAPON_AMMO) || (this.flags & FL_GODMODE))
-               instagib_stop_countdown(this);
-       else if(autocvar_g_rm && autocvar_g_rm_laser)
-       {
-               if(!this.instagib_needammo)
-               {
-                       Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_INSTAGIB_DOWNGRADE);
-                       this.instagib_needammo = true;
-               }
-       }
-       else
-       {
-               this.instagib_needammo = true;
-               if (this.health <= 5)
-               {
-                       Damage(this, this, this, 5, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_INSTAGIB_TERMINATED);
-               }
-               else if (this.health <= 10)
-               {
-                       Damage(this, this, this, 5, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_1);
-               }
-               else if (this.health <= 20)
-               {
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_2);
-               }
-               else if (this.health <= 30)
-               {
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_3);
-               }
-               else if (this.health <= 40)
-               {
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_4);
-               }
-               else if (this.health <= 50)
-               {
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_5);
-               }
-               else if (this.health <= 60)
-               {
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_6);
-               }
-               else if (this.health <= 70)
-               {
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_7);
-               }
-               else if (this.health <= 80)
-               {
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_8);
-               }
-               else if (this.health <= 90)
-               {
-                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_INSTAGIB_FINDAMMO);
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
-                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_9);
-               }
-               else
-               {
-                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_MULTI, MULTI_INSTAGIB_FINDAMMO);
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
-               }
-       }
-       this.instagib_nextthink = time + 1;
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, MatchEnd)
-{
-       FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(instagib_stop_countdown(it)));
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterDropItem)
-{
-       entity item = M_ARGV(1, entity);
-
-       item.monster_loot = spawnfunc_item_minst_cells;
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterSpawn)
-{
-       entity mon = M_ARGV(0, entity);
-
-       // always refill ammo
-       if(mon.monsterid == MON_MAGE.monsterid)
-               mon.skin = 1;
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, BotShouldAttack)
-{
-       entity targ = M_ARGV(1, entity);
-
-       if (targ.items & ITEM_Invisibility.m_itemid)
-               return true;
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, MakePlayerObserver)
-{
-       entity player = M_ARGV(0, entity);
-
-       instagib_stop_countdown(player);
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       player.effects |= EF_FULLBRIGHT;
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPreThink)
-{
-       entity player = M_ARGV(0, entity);
-
-       instagib_ammocheck(player);
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerRegen)
-{
-       // no regeneration in instagib
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPowerups)
-{
-       entity player = M_ARGV(0, entity);
-
-       if (!(player.effects & EF_FULLBRIGHT))
-               player.effects |= EF_FULLBRIGHT;
-
-       if (player.items & ITEM_Invisibility.m_itemid)
-       {
-               play_countdown(player, player.strength_finished, SND_POWEROFF);
-               if (time > player.strength_finished)
-               {
-                       player.alpha = default_player_alpha;
-                       player.exteriorweaponentity.alpha = default_weapon_alpha;
-                       player.items &= ~ITEM_Invisibility.m_itemid;
-                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY);
-               }
-       }
-       else
-       {
-               if (time < player.strength_finished)
-               {
-                       player.alpha = autocvar_g_instagib_invis_alpha;
-                       player.exteriorweaponentity.alpha = autocvar_g_instagib_invis_alpha;
-                       player.items |= ITEM_Invisibility.m_itemid;
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_INVISIBILITY, player.netname);
-                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_POWERUP_INVISIBILITY);
-               }
-       }
-
-       if (player.items & ITEM_Speed.m_itemid)
-       {
-               play_countdown(player, player.invincible_finished, SND_POWEROFF);
-               if (time > player.invincible_finished)
-               {
-                       player.items &= ~ITEM_Speed.m_itemid;
-                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_POWERDOWN_SPEED);
-               }
-       }
-       else
-       {
-               if (time < player.invincible_finished)
-               {
-                       player.items |= ITEM_Speed.m_itemid;
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_SPEED, player.netname);
-                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_POWERUP_SPEED);
-               }
-       }
-}
-
-.float stat_sv_maxspeed;
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPhysics)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.items & ITEM_Speed.m_itemid)
-               player.stat_sv_maxspeed = player.stat_sv_maxspeed * autocvar_g_instagib_speed_highspeed;
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDamage_SplitHealthArmor)
-{
-       M_ARGV(4, float) = M_ARGV(7, float); // take = damage
-       M_ARGV(5, float) = 0; // save
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, ForbidThrowCurrentWeapon)
-{
-       // weapon dropping on death handled by FilterItem
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDamage_Calculate)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-       float frag_deathtype = M_ARGV(3, float);
-       float frag_damage = M_ARGV(4, float);
-       float frag_mirrordamage = M_ARGV(5, float);
-       vector frag_force = M_ARGV(6, vector);
-
-       if(autocvar_g_friendlyfire == 0 && SAME_TEAM(frag_target, frag_attacker) && IS_PLAYER(frag_target) && IS_PLAYER(frag_attacker))
-               frag_damage = 0;
-
-       if(IS_PLAYER(frag_target))
-       {
-               if(frag_deathtype == DEATH_FALL.m_id)
-                       frag_damage = 0; // never count fall damage
-
-               if(!autocvar_g_instagib_damagedbycontents)
-               switch(DEATH_ENT(frag_deathtype))
-               {
-                       case DEATH_DROWN:
-                       case DEATH_SLIME:
-                       case DEATH_LAVA:
-                               frag_damage = 0;
-                               break;
-               }
-
-               if(IS_PLAYER(frag_attacker))
-               if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
-               {
-                       if(!autocvar_g_instagib_friendlypush && SAME_TEAM(frag_target, frag_attacker))
-                               frag_force = '0 0 0';
-
-                       if(frag_target.armorvalue)
-                       {
-                               frag_target.armorvalue -= 1;
-                               frag_damage = 0;
-                               frag_target.damage_dealt += 1;
-                               frag_attacker.damage_dealt += 1;
-                               Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_target.armorvalue);
-                       }
-               }
-
-               if(IS_PLAYER(frag_attacker) && DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
-               {
-                       if(frag_deathtype & HITTYPE_SECONDARY)
-                       {
-                               if(!autocvar_g_instagib_blaster_keepdamage || frag_attacker == frag_target)
-                               {
-                                       frag_damage = 0;
-                                       if(!autocvar_g_instagib_mirrordamage)
-                                               frag_mirrordamage = 0; // never do mirror damage on enemies
-                               }
-
-                               if(frag_target != frag_attacker)
-                               {
-                                       if(frag_damage <= 0 && frag_target.health > 0) { Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE); }
-                                       if(!autocvar_g_instagib_blaster_keepforce)
-                                               frag_force = '0 0 0';
-                               }
-                       }
-               }
-       }
-
-       if(!autocvar_g_instagib_mirrordamage) // only apply the taking lives hack if we don't want to support real damage mirroring
-       if(IS_PLAYER(frag_attacker))
-       if(frag_mirrordamage > 0)
-       {
-               // just lose extra LIVES, don't kill the player for mirror damage
-               if(frag_attacker.armorvalue > 0)
-               {
-                       frag_attacker.armorvalue -= 1;
-                       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_attacker.armorvalue);
-                       frag_attacker.damage_dealt += frag_mirrordamage;
-               }
-               frag_mirrordamage = 0;
-       }
-
-       if(frag_target.alpha && frag_target.alpha < 1)
-       if(IS_PLAYER(frag_target))
-               yoda = 1;
-
-       M_ARGV(4, float) = frag_damage;
-       M_ARGV(5, float) = frag_mirrordamage;
-       M_ARGV(6, vector) = frag_force;
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, SetStartItems)
-{
-       start_health       = warmup_start_health       = 100;
-       start_armorvalue   = warmup_start_armorvalue   = 0;
-
-       start_ammo_shells  = warmup_start_ammo_shells  = 0;
-       start_ammo_nails   = warmup_start_ammo_nails   = 0;
-       start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_instagib_ammo_start");
-       start_ammo_plasma  = warmup_start_ammo_plasma  = 0;
-       start_ammo_rockets = warmup_start_ammo_rockets = 0;
-       start_ammo_fuel    = warmup_start_ammo_fuel    = 0;
-
-       start_weapons = warmup_start_weapons = WEPSET(VAPORIZER);
-       start_items |= IT_UNLIMITED_SUPERWEAPONS;
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, FilterItem)
-{
-       entity item = M_ARGV(0, entity);
-
-       if(item.classname == "item_cells")
-               return true; // no normal cells?
-
-       if(item.weapon == WEP_VAPORIZER.m_id && item.classname == "droppedweapon")
-       {
-               item.ammo_cells = autocvar_g_instagib_ammo_drop;
-               return false;
-       }
-
-       if(item.weapon == WEP_DEVASTATOR.m_id || item.weapon == WEP_VORTEX.m_id)
-       {
-               entity e = spawn();
-               setorigin(e, item.origin);
-               e.noalign = item.noalign;
-        e.cnt = item.cnt;
-        e.team = item.team;
-        e.spawnfunc_checked = true;
-               spawnfunc_item_minst_cells(e);
-               return true;
-       }
-
-       if(item.flags & FL_POWERUP)
-               return false;
-
-       if(item.ammo_cells > autocvar_g_instagib_ammo_drop && item.classname != "item_minst_cells")
-               item.ammo_cells = autocvar_g_instagib_ammo_drop;
-
-       if(item.ammo_cells && !item.weapon)
-               return false;
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, CustomizeWaypoint)
-{
-       entity wp = M_ARGV(0, entity);
-       entity player = M_ARGV(1, entity);
-
-       entity e = WaypointSprite_getviewentity(player);
-
-       // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
-       // but only apply this to real players, not to spectators
-       if((wp.owner.flags & FL_CLIENT) && (wp.owner.items & ITEM_Invisibility.m_itemid) && (e == player))
-       if(DIFF_TEAM(wp.owner, e))
-               return true;
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDies)
-{
-       float frag_deathtype = M_ARGV(3, float);
-
-       if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
-               M_ARGV(4, float) = 1000; // always gib if it was a vaporizer death
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, ItemTouch)
-{
-       entity item = M_ARGV(0, entity);
-       entity toucher = M_ARGV(1, entity);
-
-       if(item.ammo_cells)
-       {
-               // play some cool sounds ;)
-               if (IS_CLIENT(toucher))
-               {
-                       if(toucher.health <= 5)
-                               Send_Notification(NOTIF_ONE, toucher, MSG_ANNCE, ANNCE_INSTAGIB_LASTSECOND);
-                       else if(toucher.health < 50)
-                               Send_Notification(NOTIF_ONE, toucher, MSG_ANNCE, ANNCE_INSTAGIB_NARROWLY);
-               }
-
-               if(toucher.health < 100)
-                       toucher.health = 100;
-
-               return MUT_ITEMTOUCH_CONTINUE;
-       }
-
-       if(item.itemdef == ITEM_ExtraLife)
-       {
-               toucher.armorvalue = bound(toucher.armorvalue, 999, toucher.armorvalue + autocvar_g_instagib_extralives);
-               Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_EXTRALIVES);
-               return MUT_ITEMTOUCH_PICKUP;
-       }
-
-       return MUT_ITEMTOUCH_CONTINUE;
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, OnEntityPreSpawn)
-{
-       if (!autocvar_g_powerups) { return; }
-       entity ent = M_ARGV(0, entity);
-       // Can't use .itemdef here
-       if (!(ent.classname == "item_strength" || ent.classname == "item_invincible" || ent.classname == "item_health_mega"))
-               return;
-
-       entity e = spawn();
-
-       float r = random();
-       if (r < 0.3)
-               setthink(e, instagib_invisibility);
-       else if (r < 0.6)
-               setthink(e, instagib_extralife);
-       else
-               setthink(e, instagib_speed);
-
-       e.nextthink = time + 0.1;
-       e.spawnflags = ent.spawnflags;
-       e.noalign = ent.noalign;
-       setorigin(e, ent.origin);
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":instagib");
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsPrettyString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", instagib");
-}
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, SetModname)
-{
-       M_ARGV(0, string) = "InstaGib";
-       return true;
-}
-
-#endif
-#endif
index 269ec2d245ea02cc473e1345cd02aad9b585e598..b0205a5f7b30aeb1dece55525c0943777eadbfcd 100644 (file)
@@ -1,84 +1 @@
-#pragma once
-
-#include <common/items/all.qh>
-#include <common/items/item/ammo.qh>
-#include <common/items/item/powerup.qh>
-
-float instagib_respawntime_ammo = 45;
-float instagib_respawntimejitter_ammo = 0;
-GETTER(float, instagib_respawntime_ammo)
-GETTER(float, instagib_respawntimejitter_ammo)
-
-#ifndef MENUQC
-MODEL(VaporizerCells_ITEM, Item_Model("a_cells.md3"));
-SOUND(VaporizerCells, "misc/itempickup");
-#endif
-
-REGISTER_ITEM(VaporizerCells, Ammo) {
-#ifndef MENUQC
-    this.m_model                =   MDL_VaporizerCells_ITEM;
-    this.m_sound                =   SND_VaporizerCells;
-#endif
-    this.m_name                 =   "Vaporizer Ammo";
-    this.m_icon                 =   "ammo_supercells";
-#ifdef SVQC
-    this.m_botvalue             =   100;
-    this.m_itemid               =   IT_CELLS;
-    this.m_respawntime          =   GET(instagib_respawntime_ammo);
-    this.m_respawntimejitter    =   GET(instagib_respawntimejitter_ammo);
-#endif
-}
-
-#ifndef MENUQC
-MODEL(ExtraLife_ITEM, Item_Model("g_h100.md3"));
-SOUND(ExtraLife, "misc/megahealth");
-#endif
-
-REGISTER_ITEM(ExtraLife, Powerup) {
-#ifndef MENUQC
-    this.m_model                =   MDL_ExtraLife_ITEM;
-    this.m_sound                =   SND_ExtraLife;
-#endif
-    this.m_name                 =   "Extra life";
-    this.m_icon                 =   "item_mega_health";
-    this.m_color                =   '1 0 0';
-    this.m_waypoint             =   _("Extra life");
-    this.m_waypointblink        =   2;
-    this.m_itemid               =   IT_NAILS;
-}
-
-#ifndef MENUQC
-MODEL(Invisibility_ITEM, Item_Model("g_strength.md3"));
-SOUND(Invisibility, "misc/powerup");
-#endif
-
-REGISTER_ITEM(Invisibility, Powerup) {
-#ifndef MENUQC
-    this.m_model            =   MDL_Invisibility_ITEM;
-    this.m_sound            =   SND_Invisibility;
-#endif
-    this.m_name             =   "Invisibility";
-    this.m_icon             =   "strength";
-    this.m_color            =   '0 0 1';
-    this.m_waypoint         =   _("Invisibility");
-    this.m_waypointblink    =   2;
-    this.m_itemid           =   IT_STRENGTH;
-}
-
-#ifndef MENUQC
-MODEL(Speed_ITEM, Item_Model("g_invincible.md3"));
-SOUND(Speed, "misc/powerup_shield");
-#endif
-
-REGISTER_ITEM(Speed, Powerup) {
-#ifndef MENUQC
-    this.m_model            =   MDL_Speed_ITEM;
-    this.m_sound            =   SND_Speed;
-#endif
-    this.m_name             =   "Speed";
-    this.m_icon             =   "shield";
-    this.m_color            =   '1 0 1';
-    this.m_waypoint         =   _("Speed");
-    this.m_waypointblink    =   2;
-    this.m_itemid           =   IT_INVINCIBLE;
-}
+#include "items.qh"
diff --git a/qcsrc/common/mutators/mutator/instagib/items.qh b/qcsrc/common/mutators/mutator/instagib/items.qh
new file mode 100644 (file)
index 0000000..7736fa7
--- /dev/null
@@ -0,0 +1,84 @@
+#pragma once
+
+#include <common/items/_mod.qh>
+#include <common/items/item/ammo.qh>
+#include <common/items/item/powerup.qh>
+
+float instagib_respawntime_ammo = 45;
+float instagib_respawntimejitter_ammo = 0;
+GETTER(float, instagib_respawntime_ammo)
+GETTER(float, instagib_respawntimejitter_ammo)
+
+#ifdef GAMEQC
+MODEL(VaporizerCells_ITEM, Item_Model("a_cells.md3"));
+SOUND(VaporizerCells, "misc/itempickup");
+#endif
+
+REGISTER_ITEM(VaporizerCells, Ammo) {
+#ifdef GAMEQC
+    this.m_model                =   MDL_VaporizerCells_ITEM;
+    this.m_sound                =   SND_VaporizerCells;
+#endif
+    this.m_name                 =   "Vaporizer Ammo";
+    this.m_icon                 =   "ammo_supercells";
+#ifdef SVQC
+    this.m_botvalue             =   100;
+    this.m_itemid               =   IT_CELLS;
+    this.m_respawntime          =   GET(instagib_respawntime_ammo);
+    this.m_respawntimejitter    =   GET(instagib_respawntimejitter_ammo);
+#endif
+}
+
+#ifdef GAMEQC
+MODEL(ExtraLife_ITEM, Item_Model("g_h100.md3"));
+SOUND(ExtraLife, "misc/megahealth");
+#endif
+
+REGISTER_ITEM(ExtraLife, Powerup) {
+#ifdef GAMEQC
+    this.m_model                =   MDL_ExtraLife_ITEM;
+    this.m_sound                =   SND_ExtraLife;
+#endif
+    this.m_name                 =   "Extra life";
+    this.m_icon                 =   "item_mega_health";
+    this.m_color                =   '1 0 0';
+    this.m_waypoint             =   _("Extra life");
+    this.m_waypointblink        =   2;
+    this.m_itemid               =   IT_NAILS;
+}
+
+#ifdef GAMEQC
+MODEL(Invisibility_ITEM, Item_Model("g_strength.md3"));
+SOUND(Invisibility, "misc/powerup");
+#endif
+
+REGISTER_ITEM(Invisibility, Powerup) {
+#ifdef GAMEQC
+    this.m_model            =   MDL_Invisibility_ITEM;
+    this.m_sound            =   SND_Invisibility;
+#endif
+    this.m_name             =   "Invisibility";
+    this.m_icon             =   "strength";
+    this.m_color            =   '0 0 1';
+    this.m_waypoint         =   _("Invisibility");
+    this.m_waypointblink    =   2;
+    this.m_itemid           =   IT_STRENGTH;
+}
+
+#ifdef GAMEQC
+MODEL(Speed_ITEM, Item_Model("g_invincible.md3"));
+SOUND(Speed, "misc/powerup_shield");
+#endif
+
+REGISTER_ITEM(Speed, Powerup) {
+#ifdef GAMEQC
+    this.m_model            =   MDL_Speed_ITEM;
+    this.m_sound            =   SND_Speed;
+#endif
+    this.m_name             =   "Speed";
+    this.m_icon             =   "shield";
+    this.m_color            =   '1 0 1';
+    this.m_waypoint         =   _("Speed");
+    this.m_waypointblink    =   2;
+    this.m_itemid           =   IT_INVINCIBLE;
+}
diff --git a/qcsrc/common/mutators/mutator/instagib/module.inc b/qcsrc/common/mutators/mutator/instagib/module.inc
deleted file mode 100644 (file)
index 7270067..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include "instagib.qc"
diff --git a/qcsrc/common/mutators/mutator/instagib/sv_instagib.qc b/qcsrc/common/mutators/mutator/instagib/sv_instagib.qc
new file mode 100644 (file)
index 0000000..0cf3ed9
--- /dev/null
@@ -0,0 +1,490 @@
+#include "sv_instagib.qh"
+
+int autocvar_g_instagib_ammo_drop;
+int autocvar_g_instagib_extralives;
+float autocvar_g_instagib_speed_highspeed;
+
+#include <server/client.qh>
+
+#include <common/items/_mod.qh>
+
+REGISTER_MUTATOR(mutator_instagib, cvar("g_instagib") && !g_nexball);
+
+spawnfunc(item_minst_cells)
+{
+       if (!g_instagib) { delete(this); return; }
+       if (!this.ammo_cells) this.ammo_cells = autocvar_g_instagib_ammo_drop;
+       StartItem(this, ITEM_VaporizerCells);
+}
+
+void instagib_invisibility(entity this)
+{
+       this.strength_finished = autocvar_g_balance_powerup_strength_time;
+       StartItem(this, ITEM_Invisibility);
+}
+
+void instagib_extralife(entity this)
+{
+       StartItem(this, ITEM_ExtraLife);
+}
+
+void instagib_speed(entity this)
+{
+       this.invincible_finished = autocvar_g_balance_powerup_invincible_time;
+       StartItem(this, ITEM_Speed);
+}
+
+.float instagib_nextthink;
+.float instagib_needammo;
+void instagib_stop_countdown(entity e)
+{
+       if (!e.instagib_needammo)
+               return;
+       Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER, CPID_INSTAGIB_FINDAMMO);
+       e.instagib_needammo = false;
+}
+void instagib_ammocheck(entity this)
+{
+       if(time < this.instagib_nextthink)
+               return;
+       if(!IS_PLAYER(this))
+               return; // not a player
+
+       if(IS_DEAD(this) || gameover)
+               instagib_stop_countdown(this);
+       else if (this.ammo_cells > 0 || (this.items & IT_UNLIMITED_WEAPON_AMMO) || (this.flags & FL_GODMODE))
+               instagib_stop_countdown(this);
+       else if(autocvar_g_rm && autocvar_g_rm_laser)
+       {
+               if(!this.instagib_needammo)
+               {
+                       Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_INSTAGIB_DOWNGRADE);
+                       this.instagib_needammo = true;
+               }
+       }
+       else
+       {
+               this.instagib_needammo = true;
+               if (this.health <= 5)
+               {
+                       Damage(this, this, this, 5, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_INSTAGIB_TERMINATED);
+               }
+               else if (this.health <= 10)
+               {
+                       Damage(this, this, this, 5, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_1);
+               }
+               else if (this.health <= 20)
+               {
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_2);
+               }
+               else if (this.health <= 30)
+               {
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_3);
+               }
+               else if (this.health <= 40)
+               {
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_4);
+               }
+               else if (this.health <= 50)
+               {
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_5);
+               }
+               else if (this.health <= 60)
+               {
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_6);
+               }
+               else if (this.health <= 70)
+               {
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_7);
+               }
+               else if (this.health <= 80)
+               {
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_8);
+               }
+               else if (this.health <= 90)
+               {
+                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_INSTAGIB_FINDAMMO);
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_9);
+               }
+               else
+               {
+                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_MULTI, MULTI_INSTAGIB_FINDAMMO);
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+               }
+       }
+       this.instagib_nextthink = time + 1;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, MatchEnd)
+{
+       FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(instagib_stop_countdown(it)));
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterDropItem)
+{
+       entity item = M_ARGV(1, entity);
+
+       item.monster_loot = spawnfunc_item_minst_cells;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterSpawn)
+{
+       entity mon = M_ARGV(0, entity);
+
+       // always refill ammo
+       if(mon.monsterid == MON_MAGE.monsterid)
+               mon.skin = 1;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, BotShouldAttack)
+{
+       entity targ = M_ARGV(1, entity);
+
+       if (targ.items & ITEM_Invisibility.m_itemid)
+               return true;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, MakePlayerObserver)
+{
+       entity player = M_ARGV(0, entity);
+
+       instagib_stop_countdown(player);
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       player.effects |= EF_FULLBRIGHT;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPreThink)
+{
+       entity player = M_ARGV(0, entity);
+
+       instagib_ammocheck(player);
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerRegen)
+{
+       // no regeneration in instagib
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPowerups)
+{
+       entity player = M_ARGV(0, entity);
+
+       if (!(player.effects & EF_FULLBRIGHT))
+               player.effects |= EF_FULLBRIGHT;
+
+       if (player.items & ITEM_Invisibility.m_itemid)
+       {
+               play_countdown(player, player.strength_finished, SND_POWEROFF);
+               if (time > player.strength_finished)
+               {
+                       player.alpha = default_player_alpha;
+                       player.exteriorweaponentity.alpha = default_weapon_alpha;
+                       player.items &= ~ITEM_Invisibility.m_itemid;
+                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY);
+               }
+       }
+       else
+       {
+               if (time < player.strength_finished)
+               {
+                       player.alpha = autocvar_g_instagib_invis_alpha;
+                       player.exteriorweaponentity.alpha = autocvar_g_instagib_invis_alpha;
+                       player.items |= ITEM_Invisibility.m_itemid;
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_INVISIBILITY, player.netname);
+                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_POWERUP_INVISIBILITY);
+               }
+       }
+
+       if (player.items & ITEM_Speed.m_itemid)
+       {
+               play_countdown(player, player.invincible_finished, SND_POWEROFF);
+               if (time > player.invincible_finished)
+               {
+                       player.items &= ~ITEM_Speed.m_itemid;
+                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_POWERDOWN_SPEED);
+               }
+       }
+       else
+       {
+               if (time < player.invincible_finished)
+               {
+                       player.items |= ITEM_Speed.m_itemid;
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_SPEED, player.netname);
+                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_POWERUP_SPEED);
+               }
+       }
+}
+
+.float stat_sv_maxspeed;
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPhysics)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.items & ITEM_Speed.m_itemid)
+               player.stat_sv_maxspeed = player.stat_sv_maxspeed * autocvar_g_instagib_speed_highspeed;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDamage_SplitHealthArmor)
+{
+       M_ARGV(4, float) = M_ARGV(7, float); // take = damage
+       M_ARGV(5, float) = 0; // save
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, ForbidThrowCurrentWeapon)
+{
+       // weapon dropping on death handled by FilterItem
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDamage_Calculate)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       float frag_deathtype = M_ARGV(3, float);
+       float frag_damage = M_ARGV(4, float);
+       float frag_mirrordamage = M_ARGV(5, float);
+       vector frag_force = M_ARGV(6, vector);
+
+       if(autocvar_g_friendlyfire == 0 && SAME_TEAM(frag_target, frag_attacker) && IS_PLAYER(frag_target) && IS_PLAYER(frag_attacker))
+               frag_damage = 0;
+
+       if(IS_PLAYER(frag_target))
+       {
+               if(frag_deathtype == DEATH_FALL.m_id)
+                       frag_damage = 0; // never count fall damage
+
+               if(!autocvar_g_instagib_damagedbycontents)
+               switch(DEATH_ENT(frag_deathtype))
+               {
+                       case DEATH_DROWN:
+                       case DEATH_SLIME:
+                       case DEATH_LAVA:
+                               frag_damage = 0;
+                               break;
+               }
+
+               if(IS_PLAYER(frag_attacker))
+               if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
+               {
+                       if(!autocvar_g_instagib_friendlypush && SAME_TEAM(frag_target, frag_attacker))
+                               frag_force = '0 0 0';
+
+                       if(frag_target.armorvalue)
+                       {
+                               frag_target.armorvalue -= 1;
+                               frag_damage = 0;
+                               frag_target.damage_dealt += 1;
+                               frag_attacker.damage_dealt += 1;
+                               Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_target.armorvalue);
+                       }
+               }
+
+               if(IS_PLAYER(frag_attacker) && DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
+               {
+                       if(frag_deathtype & HITTYPE_SECONDARY)
+                       {
+                               if(!autocvar_g_instagib_blaster_keepdamage || frag_attacker == frag_target)
+                               {
+                                       frag_damage = 0;
+                                       if(!autocvar_g_instagib_mirrordamage)
+                                               frag_mirrordamage = 0; // never do mirror damage on enemies
+                               }
+
+                               if(frag_target != frag_attacker)
+                               {
+                                       if(frag_damage <= 0 && frag_target.health > 0) { Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE); }
+                                       if(!autocvar_g_instagib_blaster_keepforce)
+                                               frag_force = '0 0 0';
+                               }
+                       }
+               }
+       }
+
+       if(!autocvar_g_instagib_mirrordamage) // only apply the taking lives hack if we don't want to support real damage mirroring
+       if(IS_PLAYER(frag_attacker))
+       if(frag_mirrordamage > 0)
+       {
+               // just lose extra LIVES, don't kill the player for mirror damage
+               if(frag_attacker.armorvalue > 0)
+               {
+                       frag_attacker.armorvalue -= 1;
+                       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_attacker.armorvalue);
+                       frag_attacker.damage_dealt += frag_mirrordamage;
+               }
+               frag_mirrordamage = 0;
+       }
+
+       if(frag_target.alpha && frag_target.alpha < 1)
+       if(IS_PLAYER(frag_target))
+               yoda = 1;
+
+       M_ARGV(4, float) = frag_damage;
+       M_ARGV(5, float) = frag_mirrordamage;
+       M_ARGV(6, vector) = frag_force;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, SetStartItems)
+{
+       start_health       = warmup_start_health       = 100;
+       start_armorvalue   = warmup_start_armorvalue   = 0;
+
+       start_ammo_shells  = warmup_start_ammo_shells  = 0;
+       start_ammo_nails   = warmup_start_ammo_nails   = 0;
+       start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_instagib_ammo_start");
+       start_ammo_plasma  = warmup_start_ammo_plasma  = 0;
+       start_ammo_rockets = warmup_start_ammo_rockets = 0;
+       start_ammo_fuel    = warmup_start_ammo_fuel    = 0;
+
+       start_weapons = warmup_start_weapons = WEPSET(VAPORIZER);
+       start_items |= IT_UNLIMITED_SUPERWEAPONS;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, FilterItem)
+{
+       entity item = M_ARGV(0, entity);
+
+       if(item.classname == "item_cells")
+               return true; // no normal cells?
+
+       if(item.weapon == WEP_VAPORIZER.m_id && item.classname == "droppedweapon")
+       {
+               item.ammo_cells = autocvar_g_instagib_ammo_drop;
+               return false;
+       }
+
+       if(item.weapon == WEP_DEVASTATOR.m_id || item.weapon == WEP_VORTEX.m_id)
+       {
+               entity e = spawn();
+               setorigin(e, item.origin);
+               e.noalign = item.noalign;
+        e.cnt = item.cnt;
+        e.team = item.team;
+        e.spawnfunc_checked = true;
+               spawnfunc_item_minst_cells(e);
+               return true;
+       }
+
+       if(item.flags & FL_POWERUP)
+               return false;
+
+       if(item.ammo_cells > autocvar_g_instagib_ammo_drop && item.classname != "item_minst_cells")
+               item.ammo_cells = autocvar_g_instagib_ammo_drop;
+
+       if(item.ammo_cells && !item.weapon)
+               return false;
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, CustomizeWaypoint)
+{
+       entity wp = M_ARGV(0, entity);
+       entity player = M_ARGV(1, entity);
+
+       entity e = WaypointSprite_getviewentity(player);
+
+       // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
+       // but only apply this to real players, not to spectators
+       if((wp.owner.flags & FL_CLIENT) && (wp.owner.items & ITEM_Invisibility.m_itemid) && (e == player))
+       if(DIFF_TEAM(wp.owner, e))
+               return true;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDies)
+{
+       float frag_deathtype = M_ARGV(3, float);
+
+       if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
+               M_ARGV(4, float) = 1000; // always gib if it was a vaporizer death
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, ItemTouch)
+{
+       entity item = M_ARGV(0, entity);
+       entity toucher = M_ARGV(1, entity);
+
+       if(item.ammo_cells)
+       {
+               // play some cool sounds ;)
+               if (IS_CLIENT(toucher))
+               {
+                       if(toucher.health <= 5)
+                               Send_Notification(NOTIF_ONE, toucher, MSG_ANNCE, ANNCE_INSTAGIB_LASTSECOND);
+                       else if(toucher.health < 50)
+                               Send_Notification(NOTIF_ONE, toucher, MSG_ANNCE, ANNCE_INSTAGIB_NARROWLY);
+               }
+
+               if(toucher.health < 100)
+                       toucher.health = 100;
+
+               return MUT_ITEMTOUCH_CONTINUE;
+       }
+
+       if(item.itemdef == ITEM_ExtraLife)
+       {
+               toucher.armorvalue = bound(toucher.armorvalue, 999, toucher.armorvalue + autocvar_g_instagib_extralives);
+               Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_EXTRALIVES);
+               return MUT_ITEMTOUCH_PICKUP;
+       }
+
+       return MUT_ITEMTOUCH_CONTINUE;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, OnEntityPreSpawn)
+{
+       if (!autocvar_g_powerups) { return; }
+       entity ent = M_ARGV(0, entity);
+       // Can't use .itemdef here
+       if (!(ent.classname == "item_strength" || ent.classname == "item_invincible" || ent.classname == "item_health_mega"))
+               return;
+
+       entity e = spawn();
+
+       float r = random();
+       if (r < 0.3)
+               setthink(e, instagib_invisibility);
+       else if (r < 0.6)
+               setthink(e, instagib_extralife);
+       else
+               setthink(e, instagib_speed);
+
+       e.nextthink = time + 0.1;
+       e.spawnflags = ent.spawnflags;
+       e.noalign = ent.noalign;
+       setorigin(e, ent.origin);
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":instagib");
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", instagib");
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, SetModname)
+{
+       M_ARGV(0, string) = "InstaGib";
+       return true;
+}
diff --git a/qcsrc/common/mutators/mutator/instagib/sv_instagib.qh b/qcsrc/common/mutators/mutator/instagib/sv_instagib.qh
new file mode 100644 (file)
index 0000000..4c6d20b
--- /dev/null
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "items.qh"
+
+float autocvar_g_instagib_invis_alpha;
index 68d313e95ce5608e6cc352cda79f0503f5b9b7c2..eb8c95fcb81df64309502206570ad41f6cadf47b 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/invincibleproj/invincibleproj.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/invincibleproj/sv_invincibleproj.qc>
+#endif
index dc3f32f10e8511e0cde0a654d6336ade2e6c7271..2d59a0891aa8eaf222de699744c5a0a8ccac50b5 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/invincibleproj/invincibleproj.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/invincibleproj/sv_invincibleproj.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/invincibleproj/invincibleproj.qc b/qcsrc/common/mutators/mutator/invincibleproj/invincibleproj.qc
deleted file mode 100644 (file)
index 5bdafa1..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(invincibleprojectiles, cvar("g_invincible_projectiles"));
-
-MUTATOR_HOOKFUNCTION(invincibleprojectiles, EditProjectile)
-{
-       entity proj = M_ARGV(1, entity);
-
-       if(proj.health)
-       {
-               // disable health which in effect disables damage calculations
-               proj.health = 0;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(invincibleprojectiles, BuildMutatorsString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":InvincibleProjectiles");
-}
-
-MUTATOR_HOOKFUNCTION(invincibleprojectiles, BuildMutatorsPrettyString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Invincible Projectiles");
-}
-#endif
diff --git a/qcsrc/common/mutators/mutator/invincibleproj/module.inc b/qcsrc/common/mutators/mutator/invincibleproj/module.inc
deleted file mode 100644 (file)
index 61d0383..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "invincibleproj.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/invincibleproj/sv_invincibleproj.qc b/qcsrc/common/mutators/mutator/invincibleproj/sv_invincibleproj.qc
new file mode 100644 (file)
index 0000000..23e0d0d
--- /dev/null
@@ -0,0 +1,24 @@
+#include "sv_invincibleproj.qh"
+
+REGISTER_MUTATOR(invincibleprojectiles, cvar("g_invincible_projectiles"));
+
+MUTATOR_HOOKFUNCTION(invincibleprojectiles, EditProjectile)
+{
+       entity proj = M_ARGV(1, entity);
+
+       if(proj.health)
+       {
+               // disable health which in effect disables damage calculations
+               proj.health = 0;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(invincibleprojectiles, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":InvincibleProjectiles");
+}
+
+MUTATOR_HOOKFUNCTION(invincibleprojectiles, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Invincible Projectiles");
+}
diff --git a/qcsrc/common/mutators/mutator/invincibleproj/sv_invincibleproj.qh b/qcsrc/common/mutators/mutator/invincibleproj/sv_invincibleproj.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mutators/mutator/itemstime.qc b/qcsrc/common/mutators/mutator/itemstime.qc
deleted file mode 100644 (file)
index f47923d..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(itemstime, true);
-
-REGISTER_NET_TEMP(itemstime)
-
-#ifdef SVQC
-void IT_Write(entity e, int i, float f) {
-    if (!IS_REAL_CLIENT(e)) return;
-    msg_entity = e;
-    WriteHeader(MSG_ONE, itemstime);
-    WriteByte(MSG_ONE, i);
-    WriteFloat(MSG_ONE, f);
-}
-#endif
-
-#ifdef CSQC
-// reserve one more spot for superweapons time
-float ItemsTime_time[Items_MAX + 1];
-float ItemsTime_availableTime[Items_MAX + 1];
-NET_HANDLE(itemstime, bool isNew)
-{
-    int i = ReadByte();
-    float f = ReadFloat();
-    return = true;
-    ItemsTime_time[i] = f;
-}
-#endif
-
-#ifdef CSQC
-void Item_ItemsTime_Init()
-{
-    FOREACH(Items, true, LAMBDA(
-        ItemsTime_time[it.m_id] = -1;
-    ));
-    ItemsTime_time[Items_MAX] = -1;
-}
-
-STATIC_INIT(ItemsTime_Init) {
-    Item_ItemsTime_Init();
-}
-
-int autocvar_hud_panel_itemstime = 2;
-float autocvar_hud_panel_itemstime_dynamicsize = 1;
-float autocvar_hud_panel_itemstime_ratio = 2;
-int autocvar_hud_panel_itemstime_iconalign;
-bool autocvar_hud_panel_itemstime_progressbar = 0;
-float autocvar_hud_panel_itemstime_progressbar_maxtime = 30;
-string autocvar_hud_panel_itemstime_progressbar_name = "progressbar";
-float autocvar_hud_panel_itemstime_progressbar_reduced;
-bool autocvar_hud_panel_itemstime_hidespawned = 1;
-bool autocvar_hud_panel_itemstime_hidelarge = false;
-int autocvar_hud_panel_itemstime_text = 1;
-#define hud_panel_itemstime_hidelarge autocvar_hud_panel_itemstime_hidelarge
-#else
-#define hud_panel_itemstime_hidelarge false
-#endif
-
-bool Item_ItemsTime_SpectatorOnly(GameItem it)
-{
-    return (false
-    || it == ITEM_ArmorMega     || (it == ITEM_ArmorLarge && !hud_panel_itemstime_hidelarge)
-    || it == ITEM_HealthMega    || (it == ITEM_HealthLarge && !hud_panel_itemstime_hidelarge)
-    );
-}
-
-bool Item_ItemsTime_Allow(GameItem it)
-{
-    return (false
-    || it.instanceOfPowerup
-    || Item_ItemsTime_SpectatorOnly(it)
-    );
-}
-
-#ifdef SVQC
-
-// reserve one more spot for superweapons time
-float it_times[Items_MAX + 1];
-
-void Item_ItemsTime_Init()
-{
-    FOREACH(Items, Item_ItemsTime_Allow(it), LAMBDA(
-        it_times[it.m_id] = -1;
-    ));
-    it_times[Items_MAX] = -1;
-}
-
-STATIC_INIT(ItemsTime_Init) {
-    // items time
-    Item_ItemsTime_Init();
-}
-
-void Item_ItemsTime_ResetTimes()
-{
-    FOREACH(Items, Item_ItemsTime_Allow(it), LAMBDA(
-        it_times[it.m_id] = (it_times[it.m_id] == -1) ? -1 : 0;
-    ));
-    it_times[Items_MAX] = (it_times[Items_MAX] == -1) ? -1 : 0;
-}
-
-void Item_ItemsTime_ResetTimesForPlayer(entity e)
-{
-    FOREACH(Items, Item_ItemsTime_Allow(it), LAMBDA(
-        IT_Write(e, it.m_id, (it_times[it.m_id] == -1) ? -1 : 0);
-    ));
-    IT_Write(e, Items_MAX, (it_times[Items_MAX] == -1) ? -1 : 0);
-}
-
-void Item_ItemsTime_SetTimesForPlayer(entity e)
-{
-    FOREACH(Items, Item_ItemsTime_Allow(it), LAMBDA(
-        IT_Write(e, it.m_id, it_times[it.m_id]);
-    ));
-    IT_Write(e, Items_MAX, it_times[Items_MAX]);
-}
-
-void Item_ItemsTime_SetTime(entity e, float t)
-{
-    if (!autocvar_sv_itemstime)
-        return;
-
-    GameItem item = e.itemdef;
-    if (item.instanceOfGameItem)
-    {
-               if (!item.instanceOfWeaponPickup)
-                       it_times[item.m_id] = t;
-               else if (e.weapons & WEPSET_SUPERWEAPONS)
-                       it_times[Items_MAX] = t;
-    }
-}
-
-void Item_ItemsTime_SetTimesForAllPlayers()
-{
-    FOREACH_CLIENT(IS_REAL_CLIENT(it) && (warmup_stage || !IS_PLAYER(it) || autocvar_sv_itemstime == 2), LAMBDA(Item_ItemsTime_SetTimesForPlayer(it)));
-}
-
-float Item_ItemsTime_UpdateTime(entity e, float t)
-{
-    bool isavailable = (t == 0);
-    FOREACH_ENTITY_FLOAT(pure_data, false,
-    {
-        if(!(it.itemdef == e.itemdef || ((e.weapons & WEPSET_SUPERWEAPONS) && (it.weapons & WEPSET_SUPERWEAPONS) && clienttype(it) == CLIENTTYPE_NOTACLIENT)))
-            continue;
-        if (e == it) continue;
-        if (it.scheduledrespawntime <= time)
-            isavailable = true;
-        else if (t == 0 || it.scheduledrespawntime < t)
-            t = it.scheduledrespawntime;
-    });
-    if (isavailable)
-        t = -t; // let know the client there's another available item
-    return t;
-}
-
-MUTATOR_HOOKFUNCTION(itemstime, reset_map_global)
-{
-    Item_ItemsTime_ResetTimes();
-    // ALL the times need to be reset before .reset()ing each item
-    // since Item_Reset schedules respawn of superweapons and powerups
-    FOREACH_ENTITY_FLOAT(pure_data, false,
-    {
-        if(IS_CLIENT(it))
-            continue;
-        if (it.reset) Item_ItemsTime_SetTime(it, 0);
-    });
-    Item_ItemsTime_SetTimesForAllPlayers();
-}
-
-MUTATOR_HOOKFUNCTION(itemstime, MakePlayerObserver)
-{
-    entity player = M_ARGV(0, entity);
-
-    Item_ItemsTime_SetTimesForPlayer(player);
-}
-
-MUTATOR_HOOKFUNCTION(itemstime, ClientConnect, CBC_ORDER_LAST)
-{
-    entity player = M_ARGV(0, entity);
-
-       if(IS_PLAYER(player))
-       {
-               // client became player on connection skipping putObserverInServer step
-               if (IS_REAL_CLIENT(player))
-               if (warmup_stage || autocvar_sv_itemstime == 2)
-                       Item_ItemsTime_SetTimesForPlayer(player);
-       }
-}
-
-MUTATOR_HOOKFUNCTION(itemstime, PlayerSpawn)
-{
-    if (warmup_stage || autocvar_sv_itemstime == 2) return;
-    entity player = M_ARGV(0, entity);
-
-    Item_ItemsTime_ResetTimesForPlayer(player);
-}
-
-#endif
-
-#ifdef CSQC
-
-void DrawItemsTimeItem(vector myPos, vector mySize, float ar, string item_icon, float item_time, bool item_available, float item_availableTime)
-{
-    float t = 0;
-    vector color = '0 0 0';
-    float picalpha;
-
-    if (autocvar_hud_panel_itemstime_hidespawned == 2)
-        picalpha = 1;
-    else if (item_available)
-    {
-        float BLINK_FACTOR = 0.15;
-        float BLINK_BASE = 0.85;
-        float BLINK_FREQ = 5;
-        picalpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
-    }
-    else
-        picalpha = 0.5;
-    t = floor(item_time - time + 0.999);
-    if (t < 5)
-        color = '0.7 0 0';
-    else if (t < 10)
-        color = '0.7 0.7 0';
-    else
-        color = '1 1 1';
-
-    vector picpos, numpos;
-    if (autocvar_hud_panel_itemstime_iconalign)
-    {
-        numpos = myPos;
-        picpos = myPos + eX * (ar - 1) * mySize_y;
-    }
-    else
-    {
-        numpos = myPos + eX * mySize_y;
-        picpos = myPos;
-    }
-
-    if (t > 0 && autocvar_hud_panel_itemstime_progressbar)
-    {
-        vector p_pos, p_size;
-        if (autocvar_hud_panel_itemstime_progressbar_reduced)
-        {
-            p_pos = numpos;
-            p_size = eX * ((ar - 1)/ar) * mySize_x + eY * mySize_y;
-        }
-        else
-        {
-            p_pos = myPos;
-            p_size = mySize;
-        }
-        HUD_Panel_DrawProgressBar(p_pos, p_size, autocvar_hud_panel_itemstime_progressbar_name, t/autocvar_hud_panel_itemstime_progressbar_maxtime, 0, autocvar_hud_panel_itemstime_iconalign, color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-    }
-
-    if(autocvar_hud_panel_itemstime_text)
-    {
-        if(t > 0)
-            drawstring_aspect(numpos, ftos(t), eX * ((ar - 1)/ar) * mySize_x + eY * mySize_y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
-        else if(precache_pic("gfx/hud/default/checkmark")) // COMPAT: check if this image exists, as 0.8.1 clients lack it
-            drawpic_aspect_skin(numpos, "checkmark", eX * (ar - 1) * mySize_y + eY * mySize_y, '1 1 1', panel_fg_alpha * picalpha, DRAWFLAG_NORMAL);
-        else // legacy code, if the image is missing just center the icon
-            picpos.x = myPos.x + mySize.x / 2 - mySize.y / 2;
-    }
-    if (item_availableTime)
-        drawpic_aspect_skin_expanding(picpos, item_icon, '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * picalpha, DRAWFLAG_NORMAL, item_availableTime);
-    drawpic_aspect_skin(picpos, item_icon, '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * picalpha, DRAWFLAG_NORMAL);
-}
-
-void HUD_ItemsTime()
-{
-    if (!autocvar__hud_configure)
-    {
-        if (!(
-            (autocvar_hud_panel_itemstime == 1 && spectatee_status != 0)
-        ||     (autocvar_hud_panel_itemstime == 2 && (spectatee_status != 0 || warmup_stage || STAT(ITEMSTIME) == 2))
-            )) { return; }
-    }
-    else
-    {
-        ItemsTime_time[ITEM_ArmorMega.m_id] = time + 0;
-        ItemsTime_time[ITEM_HealthMega.m_id] = time + 8;
-        ItemsTime_time[ITEM_Strength.m_id] = time + 0;
-        ItemsTime_time[ITEM_Shield.m_id] = time + 4;
-    }
-
-    int count = 0;
-    if (autocvar_hud_panel_itemstime_hidespawned == 1)
-    {
-        FOREACH(Items, Item_ItemsTime_Allow(it), LAMBDA(
-            count += (ItemsTime_time[it.m_id] > time || -ItemsTime_time[it.m_id] > time);
-        ));
-        count += (ItemsTime_time[Items_MAX] > time || -ItemsTime_time[Items_MAX] > time);
-    }
-    else if (autocvar_hud_panel_itemstime_hidespawned == 2)
-    {
-        FOREACH(Items, Item_ItemsTime_Allow(it), LAMBDA(
-            count += (ItemsTime_time[it.m_id] > time);
-        ));
-        count += (ItemsTime_time[Items_MAX] > time);
-    }
-    else
-    {
-        FOREACH(Items, Item_ItemsTime_Allow(it), LAMBDA(
-            count += (ItemsTime_time[it.m_id] != -1);
-        ));
-        count += (ItemsTime_time[Items_MAX] != -1);
-    }
-    if (count == 0)
-        return;
-
-    HUD_Panel_UpdateCvars();
-
-    vector pos, mySize;
-    pos = panel_pos;
-    mySize = panel_size;
-
-    if (panel_bg_padding)
-    {
-        pos += '1 1 0' * panel_bg_padding;
-        mySize -= '2 2 0' * panel_bg_padding;
-    }
-
-    float rows, columns;
-    float ar = max(2, autocvar_hud_panel_itemstime_ratio) + 1;
-    rows = HUD_GetRowCount(count, mySize, ar);
-    columns = ceil(count/rows);
-
-    vector itemstime_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
-
-    vector offset = '0 0 0';
-    float newSize;
-    if (autocvar_hud_panel_itemstime_dynamicsize)
-    {
-        if (autocvar__hud_configure)
-        if (hud_configure_menu_open != 2)
-            HUD_Panel_DrawBg(1); // also draw the bg of the entire panel
-
-        // reduce panel to avoid spacing items
-        if (itemstime_size.x / itemstime_size.y < ar)
-        {
-            newSize = rows * itemstime_size.x / ar;
-            pos.y += (mySize.y - newSize) / 2;
-            mySize.y = newSize;
-            itemstime_size.y = mySize.y / rows;
-        }
-        else
-        {
-            newSize = columns * itemstime_size.y * ar;
-            pos.x += (mySize.x - newSize) / 2;
-            mySize.x = newSize;
-            itemstime_size.x = mySize.x / columns;
-        }
-        panel_pos = pos - '1 1 0' * panel_bg_padding;
-        panel_size = mySize + '2 2 0' * panel_bg_padding;
-    }
-    else
-    {
-        if (itemstime_size.x/itemstime_size.y > ar)
-        {
-            newSize = ar * itemstime_size.y;
-            offset.x = itemstime_size.x - newSize;
-            pos.x += offset.x/2;
-            itemstime_size.x = newSize;
-        }
-        else
-        {
-            newSize = 1/ar * itemstime_size.x;
-            offset.y = itemstime_size.y - newSize;
-            pos.y += offset.y/2;
-            itemstime_size.y = newSize;
-        }
-    }
-
-    HUD_Scale_Enable();
-    HUD_Panel_DrawBg(1);
-
-    float row = 0, column = 0;
-    bool item_available;
-    int id = 0;
-    string icon = "";
-    FOREACH(Items, Item_ItemsTime_Allow(it) && ItemsTime_time[it.m_id] != -1, LAMBDA(
-       id = it.m_id;
-       icon = it.m_icon;
-
-LABEL(iteration)
-        float item_time = ItemsTime_time[id];
-        if (item_time < -1)
-        {
-            item_available = true;
-            item_time = -item_time;
-        }
-        else
-            item_available = (item_time <= time);
-
-        if (ItemsTime_time[id] >= 0)
-        {
-            if (time <= ItemsTime_time[id])
-                ItemsTime_availableTime[id] = 0;
-            else if (ItemsTime_availableTime[id] == 0)
-                ItemsTime_availableTime[id] = time;
-        }
-        else if (ItemsTime_availableTime[id] == 0)
-            ItemsTime_availableTime[id] = time;
-
-        float f = (time - ItemsTime_availableTime[id]) * 2;
-        f = (f > 1) ? 0 : bound(0, f, 1);
-
-        if (autocvar_hud_panel_itemstime_hidespawned == 1)
-            if (!(ItemsTime_time[id] > time || -ItemsTime_time[id] > time))
-                continue;
-
-        if (autocvar_hud_panel_itemstime_hidespawned == 2)
-            if (!(ItemsTime_time[id] > time))
-                continue;
-
-        DrawItemsTimeItem(pos + eX * column * (itemstime_size.x + offset.x) + eY * row * (itemstime_size.y + offset.y), itemstime_size, ar, icon, item_time, item_available, f);
-        ++row;
-        if (row >= rows)
-        {
-            row = 0;
-            column = column + 1;
-        }
-        if(id == Items_MAX) // can happen only in the last fake iteration
-               break;
-    ));
-    // add another fake iteration for superweapons time
-    if(id < Items_MAX && ItemsTime_time[Items_MAX] != -1)
-    {
-               id = Items_MAX;
-               icon = "superweapons";
-               goto iteration;
-    }
-}
-
-#endif
-#endif
diff --git a/qcsrc/common/mutators/mutator/itemstime/_mod.inc b/qcsrc/common/mutators/mutator/itemstime/_mod.inc
new file mode 100644 (file)
index 0000000..5b34dd6
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/mutators/mutator/itemstime/itemstime.qc>
diff --git a/qcsrc/common/mutators/mutator/itemstime/_mod.qh b/qcsrc/common/mutators/mutator/itemstime/_mod.qh
new file mode 100644 (file)
index 0000000..5c73eea
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/mutators/mutator/itemstime/itemstime.qh>
diff --git a/qcsrc/common/mutators/mutator/itemstime/itemstime.qc b/qcsrc/common/mutators/mutator/itemstime/itemstime.qc
new file mode 100644 (file)
index 0000000..b76d22e
--- /dev/null
@@ -0,0 +1,431 @@
+#include "itemstime.qh"
+
+REGISTER_MUTATOR(itemstime, true);
+
+REGISTER_NET_TEMP(itemstime)
+
+#ifdef SVQC
+void IT_Write(entity e, int i, float f) {
+    if (!IS_REAL_CLIENT(e)) return;
+    msg_entity = e;
+    WriteHeader(MSG_ONE, itemstime);
+    WriteByte(MSG_ONE, i);
+    WriteFloat(MSG_ONE, f);
+}
+#endif
+
+#ifdef CSQC
+// reserve one more spot for superweapons time
+float ItemsTime_time[Items_MAX + 1];
+float ItemsTime_availableTime[Items_MAX + 1];
+NET_HANDLE(itemstime, bool isNew)
+{
+    int i = ReadByte();
+    float f = ReadFloat();
+    return = true;
+    ItemsTime_time[i] = f;
+}
+#endif
+
+#ifdef CSQC
+void Item_ItemsTime_Init()
+{
+    FOREACH(Items, true, LAMBDA(
+        ItemsTime_time[it.m_id] = -1;
+    ));
+    ItemsTime_time[Items_MAX] = -1;
+}
+
+STATIC_INIT(ItemsTime_Init) {
+    Item_ItemsTime_Init();
+}
+
+int autocvar_hud_panel_itemstime = 2;
+float autocvar_hud_panel_itemstime_dynamicsize = 1;
+float autocvar_hud_panel_itemstime_ratio = 2;
+int autocvar_hud_panel_itemstime_iconalign;
+bool autocvar_hud_panel_itemstime_progressbar = 0;
+float autocvar_hud_panel_itemstime_progressbar_maxtime = 30;
+string autocvar_hud_panel_itemstime_progressbar_name = "progressbar";
+float autocvar_hud_panel_itemstime_progressbar_reduced;
+bool autocvar_hud_panel_itemstime_hidespawned = 1;
+bool autocvar_hud_panel_itemstime_hidelarge = false;
+int autocvar_hud_panel_itemstime_text = 1;
+#define hud_panel_itemstime_hidelarge autocvar_hud_panel_itemstime_hidelarge
+#else
+#define hud_panel_itemstime_hidelarge false
+#endif
+
+bool Item_ItemsTime_SpectatorOnly(GameItem it)
+{
+    return (false
+    || it == ITEM_ArmorMega     || (it == ITEM_ArmorLarge && !hud_panel_itemstime_hidelarge)
+    || it == ITEM_HealthMega    || (it == ITEM_HealthLarge && !hud_panel_itemstime_hidelarge)
+    );
+}
+
+bool Item_ItemsTime_Allow(GameItem it)
+{
+    return (false
+    || it.instanceOfPowerup
+    || Item_ItemsTime_SpectatorOnly(it)
+    );
+}
+
+#ifdef SVQC
+
+// reserve one more spot for superweapons time
+float it_times[Items_MAX + 1];
+
+void Item_ItemsTime_Init()
+{
+    FOREACH(Items, Item_ItemsTime_Allow(it), LAMBDA(
+        it_times[it.m_id] = -1;
+    ));
+    it_times[Items_MAX] = -1;
+}
+
+STATIC_INIT(ItemsTime_Init) {
+    // items time
+    Item_ItemsTime_Init();
+}
+
+void Item_ItemsTime_ResetTimes()
+{
+    FOREACH(Items, Item_ItemsTime_Allow(it), LAMBDA(
+        it_times[it.m_id] = (it_times[it.m_id] == -1) ? -1 : 0;
+    ));
+    it_times[Items_MAX] = (it_times[Items_MAX] == -1) ? -1 : 0;
+}
+
+void Item_ItemsTime_ResetTimesForPlayer(entity e)
+{
+    FOREACH(Items, Item_ItemsTime_Allow(it), LAMBDA(
+        IT_Write(e, it.m_id, (it_times[it.m_id] == -1) ? -1 : 0);
+    ));
+    IT_Write(e, Items_MAX, (it_times[Items_MAX] == -1) ? -1 : 0);
+}
+
+void Item_ItemsTime_SetTimesForPlayer(entity e)
+{
+    FOREACH(Items, Item_ItemsTime_Allow(it), LAMBDA(
+        IT_Write(e, it.m_id, it_times[it.m_id]);
+    ));
+    IT_Write(e, Items_MAX, it_times[Items_MAX]);
+}
+
+void Item_ItemsTime_SetTime(entity e, float t)
+{
+    if (!autocvar_sv_itemstime)
+        return;
+
+    GameItem item = e.itemdef;
+    if (item.instanceOfGameItem)
+    {
+               if (!item.instanceOfWeaponPickup)
+                       it_times[item.m_id] = t;
+               else if (e.weapons & WEPSET_SUPERWEAPONS)
+                       it_times[Items_MAX] = t;
+    }
+}
+
+void Item_ItemsTime_SetTimesForAllPlayers()
+{
+    FOREACH_CLIENT(IS_REAL_CLIENT(it) && (warmup_stage || !IS_PLAYER(it) || autocvar_sv_itemstime == 2), LAMBDA(Item_ItemsTime_SetTimesForPlayer(it)));
+}
+
+float Item_ItemsTime_UpdateTime(entity e, float t)
+{
+    bool isavailable = (t == 0);
+    IL_EACH(g_items, it != e,
+    {
+        if(!(it.itemdef == e.itemdef || ((e.weapons & WEPSET_SUPERWEAPONS) && (it.weapons & WEPSET_SUPERWEAPONS))))
+            continue;
+        if (it.scheduledrespawntime <= time)
+            isavailable = true;
+        else if (t == 0 || it.scheduledrespawntime < t)
+            t = it.scheduledrespawntime;
+    });
+    if (isavailable)
+        t = -t; // let know the client there's another available item
+    return t;
+}
+
+MUTATOR_HOOKFUNCTION(itemstime, reset_map_global)
+{
+    Item_ItemsTime_ResetTimes();
+    // ALL the times need to be reset before .reset()ing each item
+    // since Item_Reset schedules respawn of superweapons and powerups
+    IL_EACH(g_items, it.reset,
+    {
+        Item_ItemsTime_SetTime(it, 0);
+    });
+    Item_ItemsTime_SetTimesForAllPlayers();
+}
+
+MUTATOR_HOOKFUNCTION(itemstime, MakePlayerObserver)
+{
+    entity player = M_ARGV(0, entity);
+
+    Item_ItemsTime_SetTimesForPlayer(player);
+}
+
+MUTATOR_HOOKFUNCTION(itemstime, ClientConnect, CBC_ORDER_LAST)
+{
+    entity player = M_ARGV(0, entity);
+
+       if(IS_PLAYER(player))
+       {
+               // client became player on connection skipping putObserverInServer step
+               if (IS_REAL_CLIENT(player))
+               if (warmup_stage || autocvar_sv_itemstime == 2)
+                       Item_ItemsTime_SetTimesForPlayer(player);
+       }
+}
+
+MUTATOR_HOOKFUNCTION(itemstime, PlayerSpawn)
+{
+    if (warmup_stage || autocvar_sv_itemstime == 2) return;
+    entity player = M_ARGV(0, entity);
+
+    Item_ItemsTime_ResetTimesForPlayer(player);
+}
+
+#endif
+
+#ifdef CSQC
+
+void DrawItemsTimeItem(vector myPos, vector mySize, float ar, string item_icon, float item_time, bool item_available, float item_availableTime)
+{
+    float t = 0;
+    vector color = '0 0 0';
+    float picalpha;
+
+    if (autocvar_hud_panel_itemstime_hidespawned == 2)
+        picalpha = 1;
+    else if (item_available)
+    {
+        float BLINK_FACTOR = 0.15;
+        float BLINK_BASE = 0.85;
+        float BLINK_FREQ = 5;
+        picalpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
+    }
+    else
+        picalpha = 0.5;
+    t = floor(item_time - time + 0.999);
+    if (t < 5)
+        color = '0.7 0 0';
+    else if (t < 10)
+        color = '0.7 0.7 0';
+    else
+        color = '1 1 1';
+
+    vector picpos, numpos;
+    if (autocvar_hud_panel_itemstime_iconalign)
+    {
+        numpos = myPos;
+        picpos = myPos + eX * (ar - 1) * mySize_y;
+    }
+    else
+    {
+        numpos = myPos + eX * mySize_y;
+        picpos = myPos;
+    }
+
+    if (t > 0 && autocvar_hud_panel_itemstime_progressbar)
+    {
+        vector p_pos, p_size;
+        if (autocvar_hud_panel_itemstime_progressbar_reduced)
+        {
+            p_pos = numpos;
+            p_size = eX * ((ar - 1)/ar) * mySize_x + eY * mySize_y;
+        }
+        else
+        {
+            p_pos = myPos;
+            p_size = mySize;
+        }
+        HUD_Panel_DrawProgressBar(p_pos, p_size, autocvar_hud_panel_itemstime_progressbar_name, t/autocvar_hud_panel_itemstime_progressbar_maxtime, 0, autocvar_hud_panel_itemstime_iconalign, color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+    }
+
+    if(autocvar_hud_panel_itemstime_text)
+    {
+        if(t > 0)
+            drawstring_aspect(numpos, ftos(t), eX * ((ar - 1)/ar) * mySize_x + eY * mySize_y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+        else if(precache_pic("gfx/hud/default/checkmark")) // COMPAT: check if this image exists, as 0.8.1 clients lack it
+            drawpic_aspect_skin(numpos, "checkmark", eX * (ar - 1) * mySize_y + eY * mySize_y, '1 1 1', panel_fg_alpha * picalpha, DRAWFLAG_NORMAL);
+        else // legacy code, if the image is missing just center the icon
+            picpos.x = myPos.x + mySize.x / 2 - mySize.y / 2;
+    }
+    if (item_availableTime)
+        drawpic_aspect_skin_expanding(picpos, item_icon, '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * picalpha, DRAWFLAG_NORMAL, item_availableTime);
+    drawpic_aspect_skin(picpos, item_icon, '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * picalpha, DRAWFLAG_NORMAL);
+}
+
+void HUD_ItemsTime()
+{
+    if (!autocvar__hud_configure)
+    {
+        if (!(
+            (autocvar_hud_panel_itemstime == 1 && spectatee_status != 0)
+        ||     (autocvar_hud_panel_itemstime == 2 && (spectatee_status != 0 || warmup_stage || STAT(ITEMSTIME) == 2))
+            )) { return; }
+    }
+    else
+    {
+        ItemsTime_time[ITEM_ArmorMega.m_id] = time + 0;
+        ItemsTime_time[ITEM_HealthMega.m_id] = time + 8;
+        ItemsTime_time[ITEM_Strength.m_id] = time + 0;
+        ItemsTime_time[ITEM_Shield.m_id] = time + 4;
+    }
+
+    int count = 0;
+    if (autocvar_hud_panel_itemstime_hidespawned == 1)
+    {
+        FOREACH(Items, Item_ItemsTime_Allow(it), LAMBDA(
+            count += (ItemsTime_time[it.m_id] > time || -ItemsTime_time[it.m_id] > time);
+        ));
+        count += (ItemsTime_time[Items_MAX] > time || -ItemsTime_time[Items_MAX] > time);
+    }
+    else if (autocvar_hud_panel_itemstime_hidespawned == 2)
+    {
+        FOREACH(Items, Item_ItemsTime_Allow(it), LAMBDA(
+            count += (ItemsTime_time[it.m_id] > time);
+        ));
+        count += (ItemsTime_time[Items_MAX] > time);
+    }
+    else
+    {
+        FOREACH(Items, Item_ItemsTime_Allow(it), LAMBDA(
+            count += (ItemsTime_time[it.m_id] != -1);
+        ));
+        count += (ItemsTime_time[Items_MAX] != -1);
+    }
+    if (count == 0)
+        return;
+
+    HUD_Panel_LoadCvars();
+
+    vector pos, mySize;
+    pos = panel_pos;
+    mySize = panel_size;
+
+    if (panel_bg_padding)
+    {
+        pos += '1 1 0' * panel_bg_padding;
+        mySize -= '2 2 0' * panel_bg_padding;
+    }
+
+    float rows, columns;
+    float ar = max(2, autocvar_hud_panel_itemstime_ratio) + 1;
+    rows = HUD_GetRowCount(count, mySize, ar);
+    columns = ceil(count/rows);
+
+    vector itemstime_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
+
+    vector offset = '0 0 0';
+    float newSize;
+    if (autocvar_hud_panel_itemstime_dynamicsize)
+    {
+        if (autocvar__hud_configure)
+        if (hud_configure_menu_open != 2)
+            HUD_Panel_DrawBg(); // also draw the bg of the entire panel
+
+        // reduce panel to avoid spacing items
+        if (itemstime_size.x / itemstime_size.y < ar)
+        {
+            newSize = rows * itemstime_size.x / ar;
+            pos.y += (mySize.y - newSize) / 2;
+            mySize.y = newSize;
+            itemstime_size.y = mySize.y / rows;
+        }
+        else
+        {
+            newSize = columns * itemstime_size.y * ar;
+            pos.x += (mySize.x - newSize) / 2;
+            mySize.x = newSize;
+            itemstime_size.x = mySize.x / columns;
+        }
+        panel_pos = pos - '1 1 0' * panel_bg_padding;
+        panel_size = mySize + '2 2 0' * panel_bg_padding;
+    }
+    else
+    {
+        if (itemstime_size.x/itemstime_size.y > ar)
+        {
+            newSize = ar * itemstime_size.y;
+            offset.x = itemstime_size.x - newSize;
+            pos.x += offset.x/2;
+            itemstime_size.x = newSize;
+        }
+        else
+        {
+            newSize = 1/ar * itemstime_size.x;
+            offset.y = itemstime_size.y - newSize;
+            pos.y += offset.y/2;
+            itemstime_size.y = newSize;
+        }
+    }
+
+    HUD_Scale_Enable();
+    HUD_Panel_DrawBg();
+
+    float row = 0, column = 0;
+    bool item_available;
+    int id = 0;
+    string icon = "";
+    FOREACH(Items, Item_ItemsTime_Allow(it) && ItemsTime_time[it.m_id] != -1, LAMBDA(
+       id = it.m_id;
+       icon = it.m_icon;
+
+LABEL(iteration)
+        float item_time = ItemsTime_time[id];
+        if (item_time < -1)
+        {
+            item_available = true;
+            item_time = -item_time;
+        }
+        else
+            item_available = (item_time <= time);
+
+        if (ItemsTime_time[id] >= 0)
+        {
+            if (time <= ItemsTime_time[id])
+                ItemsTime_availableTime[id] = 0;
+            else if (ItemsTime_availableTime[id] == 0)
+                ItemsTime_availableTime[id] = time;
+        }
+        else if (ItemsTime_availableTime[id] == 0)
+            ItemsTime_availableTime[id] = time;
+
+        float f = (time - ItemsTime_availableTime[id]) * 2;
+        f = (f > 1) ? 0 : bound(0, f, 1);
+
+        if (autocvar_hud_panel_itemstime_hidespawned == 1)
+            if (!(ItemsTime_time[id] > time || -ItemsTime_time[id] > time))
+                continue;
+
+        if (autocvar_hud_panel_itemstime_hidespawned == 2)
+            if (!(ItemsTime_time[id] > time))
+                continue;
+
+        DrawItemsTimeItem(pos + eX * column * (itemstime_size.x + offset.x) + eY * row * (itemstime_size.y + offset.y), itemstime_size, ar, icon, item_time, item_available, f);
+        ++row;
+        if (row >= rows)
+        {
+            row = 0;
+            column = column + 1;
+        }
+        if(id == Items_MAX) // can happen only in the last fake iteration
+               break;
+    ));
+    // add another fake iteration for superweapons time
+    if(id < Items_MAX && ItemsTime_time[Items_MAX] != -1)
+    {
+               id = Items_MAX;
+               icon = "superweapons";
+               goto iteration;
+    }
+}
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/itemstime/itemstime.qh b/qcsrc/common/mutators/mutator/itemstime/itemstime.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index db31be3fddf35d6efcaf5b0876a48b40e9990f4b..da02f0808601dea33caa0dc281dd04d6b96cdd6a 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/melee_only/melee_only.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/melee_only/sv_melee_only.qc>
+#endif
index 2228d64f1844e84595b50a576947ecce36c54e2e..297bb2b9620a137d3505244621771440e6247bdd 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/melee_only/melee_only.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/melee_only/sv_melee_only.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/melee_only/melee_only.qc b/qcsrc/common/mutators/mutator/melee_only/melee_only.qc
deleted file mode 100644 (file)
index ecd5fc7..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(melee_only, cvar("g_melee_only") && !cvar("g_instagib") && !g_nexball);
-
-MUTATOR_HOOKFUNCTION(melee_only, SetStartItems)
-{
-       start_ammo_shells = warmup_start_ammo_shells = 0;
-       start_weapons = warmup_start_weapons = WEPSET(SHOTGUN);
-}
-
-MUTATOR_HOOKFUNCTION(melee_only, ForbidThrowCurrentWeapon)
-{
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(melee_only, FilterItem)
-{
-       entity item = M_ARGV(0, entity);
-
-       switch (item.items)
-       {
-               case ITEM_HealthSmall.m_itemid:
-               case ITEM_ArmorSmall.m_itemid:
-                       return false;
-       }
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(melee_only, BuildMutatorsString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":MeleeOnly");
-}
-
-MUTATOR_HOOKFUNCTION(melee_only, BuildMutatorsPrettyString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Melee Only Arena");
-}
-#endif
diff --git a/qcsrc/common/mutators/mutator/melee_only/module.inc b/qcsrc/common/mutators/mutator/melee_only/module.inc
deleted file mode 100644 (file)
index c711556..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "melee_only.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/melee_only/sv_melee_only.qc b/qcsrc/common/mutators/mutator/melee_only/sv_melee_only.qc
new file mode 100644 (file)
index 0000000..e07034b
--- /dev/null
@@ -0,0 +1,38 @@
+#include "sv_melee_only.qh"
+
+REGISTER_MUTATOR(melee_only, cvar("g_melee_only") && !cvar("g_instagib") && !g_nexball);
+
+MUTATOR_HOOKFUNCTION(melee_only, SetStartItems)
+{
+       start_ammo_shells = warmup_start_ammo_shells = 0;
+       start_weapons = warmup_start_weapons = WEPSET(SHOTGUN);
+}
+
+MUTATOR_HOOKFUNCTION(melee_only, ForbidThrowCurrentWeapon)
+{
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(melee_only, FilterItem)
+{
+       entity item = M_ARGV(0, entity);
+
+       switch (item.items)
+       {
+               case ITEM_HealthSmall.m_itemid:
+               case ITEM_ArmorSmall.m_itemid:
+                       return false;
+       }
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(melee_only, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":MeleeOnly");
+}
+
+MUTATOR_HOOKFUNCTION(melee_only, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Melee Only Arena");
+}
diff --git a/qcsrc/common/mutators/mutator/melee_only/sv_melee_only.qh b/qcsrc/common/mutators/mutator/melee_only/sv_melee_only.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 8fcc96ea218b6810bdc65416d997fe14e2f38e42..b144ca4b6aea060507cb3b9d13cd239996b25132 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/midair/midair.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/midair/sv_midair.qc>
+#endif
index 48272b8709032972b531a2c262eb100259150ada..f96da138670e5e2891db759371d3fe22d6761331 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/midair/midair.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/midair/sv_midair.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/midair/midair.qc b/qcsrc/common/mutators/mutator/midair/midair.qc
deleted file mode 100644 (file)
index 1fa69a6..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifdef IMPLEMENTATION
-
-float autocvar_g_midair_shieldtime;
-
-REGISTER_MUTATOR(midair, cvar("g_midair"));
-
-.float midair_shieldtime;
-
-MUTATOR_HOOKFUNCTION(midair, PlayerDamage_Calculate)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-
-       if(IS_PLAYER(frag_attacker))
-       if(IS_PLAYER(frag_target))
-       if(time < frag_target.midair_shieldtime)
-               M_ARGV(4, float) = 0;
-}
-
-MUTATOR_HOOKFUNCTION(midair, PlayerPowerups)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(time >= game_starttime)
-       if(IS_ONGROUND(player))
-       {
-               player.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
-               player.midair_shieldtime = max(player.midair_shieldtime, time + autocvar_g_midair_shieldtime);
-       }
-}
-
-MUTATOR_HOOKFUNCTION(midair, PlayerSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(IS_BOT_CLIENT(player))
-               player.bot_moveskill = 0; // disable bunnyhopping
-}
-
-MUTATOR_HOOKFUNCTION(midair, BuildMutatorsString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":midair");
-}
-
-MUTATOR_HOOKFUNCTION(midair, BuildMutatorsPrettyString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Midair");
-}
-#endif
diff --git a/qcsrc/common/mutators/mutator/midair/module.inc b/qcsrc/common/mutators/mutator/midair/module.inc
deleted file mode 100644 (file)
index 10b1789..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "midair.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/midair/sv_midair.qc b/qcsrc/common/mutators/mutator/midair/sv_midair.qc
new file mode 100644 (file)
index 0000000..40747ff
--- /dev/null
@@ -0,0 +1,48 @@
+#include "sv_midair.qh"
+
+float autocvar_g_midair_shieldtime;
+
+REGISTER_MUTATOR(midair, cvar("g_midair"));
+
+.float midair_shieldtime;
+
+MUTATOR_HOOKFUNCTION(midair, PlayerDamage_Calculate)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+
+       if(IS_PLAYER(frag_attacker))
+       if(IS_PLAYER(frag_target))
+       if(time < frag_target.midair_shieldtime)
+               M_ARGV(4, float) = 0;
+}
+
+MUTATOR_HOOKFUNCTION(midair, PlayerPowerups)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(time >= game_starttime)
+       if(IS_ONGROUND(player))
+       {
+               player.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
+               player.midair_shieldtime = max(player.midair_shieldtime, time + autocvar_g_midair_shieldtime);
+       }
+}
+
+MUTATOR_HOOKFUNCTION(midair, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(IS_BOT_CLIENT(player))
+               player.bot_moveskill = 0; // disable bunnyhopping
+}
+
+MUTATOR_HOOKFUNCTION(midair, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":midair");
+}
+
+MUTATOR_HOOKFUNCTION(midair, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Midair");
+}
diff --git a/qcsrc/common/mutators/mutator/midair/sv_midair.qh b/qcsrc/common/mutators/mutator/midair/sv_midair.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mutators/mutator/multijump/module.inc b/qcsrc/common/mutators/mutator/multijump/module.inc
deleted file mode 100644 (file)
index 3103320..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifndef MENUQC
-#include "multijump.qc"
-#endif
index d6dc30cee4ec16d0ce8d4a3e899376ab6b429575..ecedc475961585184fd61bad6785d2986f00f23e 100644 (file)
@@ -1,4 +1,7 @@
-#ifdef IMPLEMENTATION
+#include "multijump.qh"
+
+#ifdef GAMEQC
+
 #ifdef SVQC
        #include <server/antilag.qh>
 #endif
@@ -126,4 +129,5 @@ MUTATOR_HOOKFUNCTION(multijump, BuildMutatorsPrettyString)
 }
 
 #endif
+
 #endif
diff --git a/qcsrc/common/mutators/mutator/multijump/multijump.qh b/qcsrc/common/mutators/mutator/multijump/multijump.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mutators/mutator/nades/module.inc b/qcsrc/common/mutators/mutator/nades/module.inc
deleted file mode 100644 (file)
index e03900d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#include "nades.qc"
-#ifndef MENUQC
-#include "net.qc"
-#endif
index 8a7337f6103a9020849196832b0e24484f9d21be..bcdbe0cd920973e256c142f27d1d216ef8e90f02 100644 (file)
@@ -1,4 +1,4 @@
-#ifndef MENUQC
+#ifdef GAMEQC
 #define NADE_PROJECTILE(i, projectile, trail) MACRO_BEGIN { \
     this.m_projectile[i] = projectile; \
     this.m_trail[i] = trail; \
index d785124a76e6698bc139ffe2d38134a975cba50c..c4e73d286d13946e64024fc976ae1d5987e3347a 100644 (file)
@@ -1,7 +1,5 @@
 #include "nades.qh"
 
-#ifdef IMPLEMENTATION
-
 #ifdef SVQC
 bool autocvar_g_nades_nade_small;
 float autocvar_g_nades_spread = 0.04;
@@ -9,7 +7,7 @@ float autocvar_g_nades_spread = 0.04;
 
 REGISTER_STAT(NADES_SMALL, int, autocvar_g_nades_nade_small)
 
-#ifndef MENUQC
+#ifdef GAMEQC
 entity Nade_TrailEffect(int proj, int nade_team)
 {
     switch (proj)
@@ -147,8 +145,8 @@ void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expan
 
 #ifdef SVQC
 
-#include <common/gamemodes/all.qh>
-#include <common/monsters/spawn.qh>
+#include <common/gamemodes/_mod.qh>
+#include <common/monsters/sv_spawn.qh>
 #include <common/monsters/sv_monsters.qh>
 #include <server/g_subs.qh>
 
@@ -295,6 +293,7 @@ void nade_napalm_ball(entity this)
        proj.angles = vectoangles(proj.velocity);
        proj.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, proj);
+       IL_PUSH(g_bot_dodge, proj);
        proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC;
 
        //CSQCProjectile(proj, true, PROJECTILE_NAPALM_FIRE, true);
@@ -351,6 +350,9 @@ void nade_napalm_boom(entity this)
        fountain.owner = this.owner;
        fountain.realowner = this.realowner;
        fountain.origin = this.origin;
+       fountain.flags = FL_PROJECTILE;
+       IL_PUSH(g_projectiles, fountain);
+       IL_PUSH(g_bot_dodge, fountain);
        setorigin(fountain, fountain.origin);
        setthink(fountain, napalm_fountain_think);
        fountain.nextthink = time;
@@ -732,10 +734,9 @@ void nade_boom(entity this)
                case NADE_TYPE_ENTRAP: nade_entrap_boom(this); break;
        }
 
-       FOREACH_ENTITY_ENT(aiment, this,
+       IL_EACH(g_projectiles, it.classname == "grapplinghook" && it.aiment == this,
        {
-               if(it.classname == "grapplinghook")
-                       RemoveGrapplingHook(it.realowner);
+               RemoveGrapplingHook(it.realowner);
        });
 
        delete(this);
@@ -782,10 +783,9 @@ void nade_touch(entity this, entity toucher)
                is_weapclip = 1;*/
        if(ITEM_TOUCH_NEEDKILL()) // || is_weapclip)
        {
-               FOREACH_ENTITY_ENT(aiment, this,
+               IL_EACH(g_projectiles, it.classname == "grapplinghook" && it.aiment == this,
                {
-                       if(it.classname == "grapplinghook")
-                               RemoveGrapplingHook(it.realowner);
+                       RemoveGrapplingHook(it.realowner);
                });
                delete(this);
                return;
@@ -944,6 +944,7 @@ void toss_nade(entity e, bool set_owner, vector _velocity, float _time)
        _nade.angles = vectoangles(_nade.velocity);
        _nade.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, _nade);
+       IL_PUSH(g_bot_dodge, _nade);
        _nade.projectiledeathtype = DEATH_NADE.m_id;
        _nade.toss_time = time;
        _nade.solid = SOLID_CORPSE; //((_nade.nade_type == NADE_TYPE_TRANSLOCATE) ? SOLID_CORPSE : SOLID_BBOX);
@@ -1486,4 +1487,3 @@ MUTATOR_HOOKFUNCTION(nades, BuildGameplayTipsString)
 }
 
 #endif
-#endif
index a7eed65d33aceb29f20ee28d94228ad3eb2a4331..fd8d26902a4f5b6665dd2238c83c4d0f9708a26d 100644 (file)
@@ -1,5 +1,4 @@
-#ifndef NADES_ALL_H
-#define NADES_ALL_H
+#pragma once
 
 #include <common/teams.qh>
 
@@ -52,7 +51,7 @@ Nade Nade_FromProjectile(int proj)
     return NADE_TYPE_Null;
 }
 
-#ifndef MENUQC
+#ifdef GAMEQC
 #include "effects.inc"
 #endif
 
@@ -86,7 +85,7 @@ bool orb_send(entity this, entity to, int sf);
 void nades_Clear(entity player);
 
 // Give a bonus grenade to a player
-void(entity player, float score) nades_GiveBonus;
+void nades_GiveBonus(entity player, float score);
 
 /**
  * called to adjust nade damage and force on hit
@@ -102,5 +101,3 @@ void(entity player, float score) nades_GiveBonus;
 MUTATOR_HOOKABLE(Nade_Damage, EV_Nade_Damage);
 
 #endif
-
-#endif
index e2659c7af85307fb2e30529e1318b83e35a12746..498d878d2d272341bd2ba9b04fd8908393a5e713 100644 (file)
@@ -1,6 +1,8 @@
-#include "nades.qh"
+#include "net.qh"
+
+#ifdef GAMEQC
 
-#ifdef IMPLEMENTATION
+#include "nades.qh"
 
 #ifdef CSQC
 .float ltime;
diff --git a/qcsrc/common/mutators/mutator/nades/net.qh b/qcsrc/common/mutators/mutator/nades/net.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 90e9811ea6c0a3196e660f8ccb73f5d50e5c7298..67ee4f5345734f58eaaea95f827fbbef7a20ec90 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/new_toys/new_toys.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/new_toys/sv_new_toys.qc>
+#endif
index ec3b8105fe0e7b88cc61ebce4b6035f944957c78..97f88a519200c6ce1c25866b027453560a9e6d9f 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/new_toys/new_toys.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/new_toys/sv_new_toys.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/new_toys/module.inc b/qcsrc/common/mutators/mutator/new_toys/module.inc
deleted file mode 100644 (file)
index 1217177..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "new_toys.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/new_toys/new_toys.qc b/qcsrc/common/mutators/mutator/new_toys/new_toys.qc
deleted file mode 100644 (file)
index 27d1795..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-#ifdef IMPLEMENTATION
-/*
-
-CORE    laser   vortex     lg      rl      cry     gl      elec    hagar   fireb   hook
-                                                                       vaporizer  porto
-                                                                       tuba
-
-NEW             rifle   hlac    minel                           seeker
-IDEAS                                   OPEN    flak    OPEN            FUN FUN FUN FUN
-
-
-
-How this mutator works:
- =======================
-
-When a gun tries to spawn, this mutator is called. It will provide alternate
-weaponreplace lists.
-
-Entity:
-
-{
-"classname" "weapon_vortex"
-"new_toys" "rifle"
-}
--> This will spawn as Rifle in this mutator ONLY, and as Vortex otherwise.
-
-{
-"classname" "weapon_vortext"
-"new_toys" "vortex rifle"
-}
--> This will spawn as either Vortex or Rifle in this mutator ONLY, and as Vortex otherwise.
-
-{
-"classname" "weapon_vortex"
-"new_toys" "vortex"
-}
--> This is always a Vortex.
-
-If the map specifies no "new_toys" argument
-
-There will be two default replacements selectable: "replace all" and "replace random".
-In "replace all" mode, e.g. Vortex will have the default replacement "rifle".
-In "replace random" mode, Vortex will have the default replacement "vortex rifle".
-
-This mutator's replacements run BEFORE regular weaponreplace!
-
-The New Toys guns do NOT get a spawn function, so they can only ever be spawned
-when this mutator is active.
-
-Likewise, warmup, give all, give ALL and impulse 99 will not give them unless
-this mutator is active.
-
-Outside this mutator, they still can be spawned by:
-- setting their start weapon cvar to 1
-- give weaponname
-- weaponreplace
-- weaponarena (but all and most weapons arena again won't include them)
-
-This mutator performs the default replacements on the DEFAULTS of the
-start weapon selection.
-
-These weapons appear in the menu's priority list, BUT get a suffix
-"(Mutator weapon)".
-
-Picking up a "new toys" weapon will not play standard weapon pickup sound, but
-roflsound "New toys, new toys!" sound.
-
-*/
-
-bool nt_IsNewToy(int w);
-
-REGISTER_MUTATOR(nt, cvar("g_new_toys") && !cvar("g_instagib") && !cvar("g_overkill"))
-{
-       MUTATOR_ONADD
-       {
-               if(time > 1) // game loads at time 1
-                       error("This cannot be added at runtime\n");
-
-               // mark the guns as ok to use by e.g. impulse 99
-               FOREACH(Weapons, it != WEP_Null, LAMBDA(
-                       if(nt_IsNewToy(it.m_id))
-                               it.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-               ));
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               FOREACH(Weapons, it != WEP_Null, LAMBDA(
-                       if(nt_IsNewToy(it.m_id))
-                               it.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-               ));
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This cannot be removed at runtime\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-.string new_toys;
-
-float autocvar_g_new_toys_autoreplace;
-bool autocvar_g_new_toys_use_pickupsound = true;
-const float NT_AUTOREPLACE_NEVER = 0;
-const float NT_AUTOREPLACE_ALWAYS = 1;
-const float NT_AUTOREPLACE_RANDOM = 2;
-
-MUTATOR_HOOKFUNCTION(nt, SetModname)
-{
-       M_ARGV(0, string) = "NewToys";
-}
-
-bool nt_IsNewToy(int w)
-{
-       switch(w)
-       {
-               case WEP_SEEKER.m_id:
-               case WEP_MINE_LAYER.m_id:
-               case WEP_HLAC.m_id:
-               case WEP_RIFLE.m_id:
-               case WEP_SHOCKWAVE.m_id:
-                       return true;
-               default:
-                       return false;
-       }
-}
-
-string nt_GetFullReplacement(string w)
-{
-       switch(w)
-       {
-               case "hagar": return "seeker";
-               case "devastator": return "minelayer";
-               case "machinegun": return "hlac";
-               case "vortex": return "rifle";
-               //case "shotgun": return "shockwave";
-               default: return string_null;
-       }
-}
-
-string nt_GetReplacement(string w, float m)
-{
-       if(m == NT_AUTOREPLACE_NEVER)
-               return w;
-       string s = nt_GetFullReplacement(w);
-       if (!s)
-               return w;
-       if(m == NT_AUTOREPLACE_RANDOM)
-               s = strcat(w, " ", s);
-       return s;
-}
-
-MUTATOR_HOOKFUNCTION(nt, SetStartItems)
-{
-       // rearrange start_weapon_default
-       // apply those bits that are set by start_weapon_defaultmask
-       // same for warmup
-
-       float j, n;
-
-       WepSet newdefault;
-       WepSet warmup_newdefault;
-
-       newdefault = '0 0 0';
-       warmup_newdefault = '0 0 0';
-
-       WepSet seti = '0 0 0';
-
-       FOREACH(Weapons, it != WEP_Null, LAMBDA(
-               seti = it.m_wepset;
-               n = tokenize_console(nt_GetReplacement(it.netname, autocvar_g_new_toys_autoreplace));
-
-               for(j = 0; j < n; ++j)
-                       FOREACH(Weapons, it != WEP_Null, LAMBDA(
-                               if(it.netname == argv(j))
-                               {
-                                       WepSet setk = it.m_wepset;
-                                       if(start_weapons & seti) newdefault |= setk;
-                                       if(warmup_start_weapons & seti) warmup_newdefault |= setk;
-                               }
-                       ));
-       ));
-
-       newdefault &= start_weapons_defaultmask;
-       start_weapons &= ~start_weapons_defaultmask;
-       start_weapons |= newdefault;
-
-       warmup_newdefault &= warmup_start_weapons_defaultmask;
-       warmup_start_weapons &= ~warmup_start_weapons_defaultmask;
-       warmup_start_weapons |= warmup_newdefault;
-}
-
-MUTATOR_HOOKFUNCTION(nt, SetWeaponreplace)
-{
-       entity wep = M_ARGV(0, entity);
-       entity wepinfo = M_ARGV(1, entity);
-       string ret_string = M_ARGV(2, string);
-
-       // otherwise, we do replace
-       if(wep.new_toys)
-       {
-               // map defined replacement:
-               ret_string = wep.new_toys;
-       }
-       else
-       {
-               // auto replacement:
-               ret_string = nt_GetReplacement(wepinfo.netname, autocvar_g_new_toys_autoreplace);
-       }
-
-       // apply regular weaponreplace
-       ret_string = W_Apply_Weaponreplace(ret_string);
-
-       M_ARGV(2, string) = ret_string;
-}
-
-MUTATOR_HOOKFUNCTION(nt, FilterItem)
-{
-       entity item = M_ARGV(0, entity);
-
-       if(nt_IsNewToy(item.weapon) && autocvar_g_new_toys_use_pickupsound) {
-               item.item_pickupsound = string_null;
-               item.item_pickupsound_ent = SND_WEAPONPICKUP_NEW_TOYS;
-       }
-}
-#endif
diff --git a/qcsrc/common/mutators/mutator/new_toys/sv_new_toys.qc b/qcsrc/common/mutators/mutator/new_toys/sv_new_toys.qc
new file mode 100644 (file)
index 0000000..6c0647b
--- /dev/null
@@ -0,0 +1,229 @@
+#include "sv_new_toys.qh"
+
+/*
+
+CORE    laser   vortex     lg      rl      cry     gl      elec    hagar   fireb   hook
+                                                                       vaporizer  porto
+                                                                       tuba
+
+NEW             rifle   hlac    minel                           seeker
+IDEAS                                   OPEN    flak    OPEN            FUN FUN FUN FUN
+
+
+
+How this mutator works:
+ =======================
+
+When a gun tries to spawn, this mutator is called. It will provide alternate
+weaponreplace lists.
+
+Entity:
+
+{
+"classname" "weapon_vortex"
+"new_toys" "rifle"
+}
+-> This will spawn as Rifle in this mutator ONLY, and as Vortex otherwise.
+
+{
+"classname" "weapon_vortext"
+"new_toys" "vortex rifle"
+}
+-> This will spawn as either Vortex or Rifle in this mutator ONLY, and as Vortex otherwise.
+
+{
+"classname" "weapon_vortex"
+"new_toys" "vortex"
+}
+-> This is always a Vortex.
+
+If the map specifies no "new_toys" argument
+
+There will be two default replacements selectable: "replace all" and "replace random".
+In "replace all" mode, e.g. Vortex will have the default replacement "rifle".
+In "replace random" mode, Vortex will have the default replacement "vortex rifle".
+
+This mutator's replacements run BEFORE regular weaponreplace!
+
+The New Toys guns do NOT get a spawn function, so they can only ever be spawned
+when this mutator is active.
+
+Likewise, warmup, give all, give ALL and impulse 99 will not give them unless
+this mutator is active.
+
+Outside this mutator, they still can be spawned by:
+- setting their start weapon cvar to 1
+- give weaponname
+- weaponreplace
+- weaponarena (but all and most weapons arena again won't include them)
+
+This mutator performs the default replacements on the DEFAULTS of the
+start weapon selection.
+
+These weapons appear in the menu's priority list, BUT get a suffix
+"(Mutator weapon)".
+
+Picking up a "new toys" weapon will not play standard weapon pickup sound, but
+roflsound "New toys, new toys!" sound.
+
+*/
+
+bool nt_IsNewToy(int w);
+
+REGISTER_MUTATOR(nt, cvar("g_new_toys") && !cvar("g_instagib") && !cvar("g_overkill"))
+{
+       MUTATOR_ONADD
+       {
+               if(time > 1) // game loads at time 1
+                       error("This cannot be added at runtime\n");
+
+               // mark the guns as ok to use by e.g. impulse 99
+               FOREACH(Weapons, it != WEP_Null, LAMBDA(
+                       if(nt_IsNewToy(it.m_id))
+                               it.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+               ));
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               FOREACH(Weapons, it != WEP_Null, LAMBDA(
+                       if(nt_IsNewToy(it.m_id))
+                               it.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+               ));
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This cannot be removed at runtime\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+.string new_toys;
+
+float autocvar_g_new_toys_autoreplace;
+bool autocvar_g_new_toys_use_pickupsound = true;
+const float NT_AUTOREPLACE_NEVER = 0;
+const float NT_AUTOREPLACE_ALWAYS = 1;
+const float NT_AUTOREPLACE_RANDOM = 2;
+
+MUTATOR_HOOKFUNCTION(nt, SetModname)
+{
+       M_ARGV(0, string) = "NewToys";
+}
+
+bool nt_IsNewToy(int w)
+{
+       switch(w)
+       {
+               case WEP_SEEKER.m_id:
+               case WEP_MINE_LAYER.m_id:
+               case WEP_HLAC.m_id:
+               case WEP_RIFLE.m_id:
+               case WEP_SHOCKWAVE.m_id:
+                       return true;
+               default:
+                       return false;
+       }
+}
+
+string nt_GetFullReplacement(string w)
+{
+       switch(w)
+       {
+               case "hagar": return "seeker";
+               case "devastator": return "minelayer";
+               case "machinegun": return "hlac";
+               case "vortex": return "rifle";
+               //case "shotgun": return "shockwave";
+               default: return string_null;
+       }
+}
+
+string nt_GetReplacement(string w, float m)
+{
+       if(m == NT_AUTOREPLACE_NEVER)
+               return w;
+       string s = nt_GetFullReplacement(w);
+       if (!s)
+               return w;
+       if(m == NT_AUTOREPLACE_RANDOM)
+               s = strcat(w, " ", s);
+       return s;
+}
+
+MUTATOR_HOOKFUNCTION(nt, SetStartItems)
+{
+       // rearrange start_weapon_default
+       // apply those bits that are set by start_weapon_defaultmask
+       // same for warmup
+
+       float j, n;
+
+       WepSet newdefault;
+       WepSet warmup_newdefault;
+
+       newdefault = '0 0 0';
+       warmup_newdefault = '0 0 0';
+
+       WepSet seti = '0 0 0';
+
+       FOREACH(Weapons, it != WEP_Null, LAMBDA(
+               seti = it.m_wepset;
+               n = tokenize_console(nt_GetReplacement(it.netname, autocvar_g_new_toys_autoreplace));
+
+               for(j = 0; j < n; ++j)
+                       FOREACH(Weapons, it != WEP_Null, LAMBDA(
+                               if(it.netname == argv(j))
+                               {
+                                       WepSet setk = it.m_wepset;
+                                       if(start_weapons & seti) newdefault |= setk;
+                                       if(warmup_start_weapons & seti) warmup_newdefault |= setk;
+                               }
+                       ));
+       ));
+
+       newdefault &= start_weapons_defaultmask;
+       start_weapons &= ~start_weapons_defaultmask;
+       start_weapons |= newdefault;
+
+       warmup_newdefault &= warmup_start_weapons_defaultmask;
+       warmup_start_weapons &= ~warmup_start_weapons_defaultmask;
+       warmup_start_weapons |= warmup_newdefault;
+}
+
+MUTATOR_HOOKFUNCTION(nt, SetWeaponreplace)
+{
+       entity wep = M_ARGV(0, entity);
+       entity wepinfo = M_ARGV(1, entity);
+       string ret_string = M_ARGV(2, string);
+
+       // otherwise, we do replace
+       if(wep.new_toys)
+       {
+               // map defined replacement:
+               ret_string = wep.new_toys;
+       }
+       else
+       {
+               // auto replacement:
+               ret_string = nt_GetReplacement(wepinfo.netname, autocvar_g_new_toys_autoreplace);
+       }
+
+       // apply regular weaponreplace
+       ret_string = W_Apply_Weaponreplace(ret_string);
+
+       M_ARGV(2, string) = ret_string;
+}
+
+MUTATOR_HOOKFUNCTION(nt, FilterItem)
+{
+       entity item = M_ARGV(0, entity);
+
+       if(nt_IsNewToy(item.weapon) && autocvar_g_new_toys_use_pickupsound) {
+               item.item_pickupsound = string_null;
+               item.item_pickupsound_ent = SND_WEAPONPICKUP_NEW_TOYS;
+       }
+}
diff --git a/qcsrc/common/mutators/mutator/new_toys/sv_new_toys.qh b/qcsrc/common/mutators/mutator/new_toys/sv_new_toys.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index a669175da2ebb221b895e42cf63407202f1dccb3..3c3141d6fb1455d2fcaecd6a86fb911ef8fe1794 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/nix/nix.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/nix/sv_nix.qc>
+#endif
index 6c012fe65c5b09c7c92f63291faa920367c429eb..affbae20a90d35e726d0bd07f01ce9cf1441e930 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/nix/nix.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/nix/sv_nix.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/nix/module.inc b/qcsrc/common/mutators/mutator/nix/module.inc
deleted file mode 100644 (file)
index fb4f9ec..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "nix.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/nix/nix.qc b/qcsrc/common/mutators/mutator/nix/nix.qc
deleted file mode 100644 (file)
index f52d75a..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-#ifdef IMPLEMENTATION
-int autocvar_g_balance_nix_ammo_cells;
-int autocvar_g_balance_nix_ammo_plasma;
-int autocvar_g_balance_nix_ammo_fuel;
-int autocvar_g_balance_nix_ammo_nails;
-int autocvar_g_balance_nix_ammo_rockets;
-int autocvar_g_balance_nix_ammo_shells;
-int autocvar_g_balance_nix_ammoincr_cells;
-int autocvar_g_balance_nix_ammoincr_plasma;
-int autocvar_g_balance_nix_ammoincr_fuel;
-int autocvar_g_balance_nix_ammoincr_nails;
-int autocvar_g_balance_nix_ammoincr_rockets;
-int autocvar_g_balance_nix_ammoincr_shells;
-float autocvar_g_balance_nix_incrtime;
-float autocvar_g_balance_nix_roundtime;
-bool autocvar_g_nix_with_healtharmor;
-bool autocvar_g_nix_with_blaster;
-bool autocvar_g_nix_with_powerups;
-int autocvar_g_pickup_cells_max;
-int autocvar_g_pickup_plasma_max;
-int autocvar_g_pickup_fuel_max;
-int autocvar_g_pickup_nails_max;
-int autocvar_g_pickup_rockets_max;
-int autocvar_g_pickup_shells_max;
-
-float g_nix_with_blaster;
-// WEAPONTODO
-int nix_weapon;
-float nix_nextchange;
-float nix_nextweapon;
-.float nix_lastchange_id;
-.float nix_lastinfotime;
-.float nix_nextincr;
-
-bool NIX_CanChooseWeapon(int wpn);
-
-REGISTER_MUTATOR(nix, cvar("g_nix") && !cvar("g_instagib") && !cvar("g_overkill"))
-{
-       MUTATOR_ONADD
-       {
-               g_nix_with_blaster = autocvar_g_nix_with_blaster;
-
-               nix_nextchange = 0;
-               nix_nextweapon = 0;
-
-               FOREACH(Weapons, it != WEP_Null && NIX_CanChooseWeapon(it.m_id), LAMBDA(it.wr_init(it)));
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // nothing to roll back
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               // as the PlayerSpawn hook will no longer run, NIX is turned off by this!
-               FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
-                       it.ammo_cells = start_ammo_cells;
-                       it.ammo_plasma = start_ammo_plasma;
-                       it.ammo_shells = start_ammo_shells;
-                       it.ammo_nails = start_ammo_nails;
-                       it.ammo_rockets = start_ammo_rockets;
-                       it.ammo_fuel = start_ammo_fuel;
-                       it.weapons = start_weapons;
-                       if(!client_hasweapon(it, PS(it).m_weapon, true, false))
-                               PS(it).m_switchweapon = w_getbestweapon(it);
-               });
-       }
-
-       return false;
-}
-
-bool NIX_CanChooseWeapon(int wpn)
-{
-       entity e = Weapons_from(wpn);
-       if (e == WEP_Null) return false; // skip dummies
-       if(g_weaponarena)
-       {
-               if(!(g_weaponarena_weapons & e.m_wepset))
-                       return false;
-       }
-       else
-       {
-               if(wpn == WEP_BLASTER.m_id && g_nix_with_blaster)
-                       return false;
-               if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
-                       return false;
-               if (!(e.spawnflags & WEP_FLAG_NORMAL))
-                       return false;
-       }
-       return true;
-}
-void NIX_ChooseNextWeapon()
-{
-       RandomSelection_Init();
-       FOREACH(Weapons, it != WEP_Null, LAMBDA(
-               if(NIX_CanChooseWeapon(it.m_id))
-                       RandomSelection_Add(NULL, it.m_id, string_null, 1, (it.m_id != nix_weapon));
-       ));
-       nix_nextweapon = RandomSelection_chosen_float;
-}
-
-void NIX_GiveCurrentWeapon(entity this)
-{
-       float dt;
-
-       if(!nix_nextweapon)
-               NIX_ChooseNextWeapon();
-
-       dt = ceil(nix_nextchange - time);
-
-       if(dt <= 0)
-       {
-               nix_weapon = nix_nextweapon;
-               nix_nextweapon = 0;
-               if (!nix_nextchange) // no round played yet?
-                       nix_nextchange = time; // start the first round now!
-               else
-                       nix_nextchange = time + autocvar_g_balance_nix_roundtime;
-               // Weapon w = Weapons_from(nix_weapon);
-               // w.wr_init(w); // forget it, too slow
-       }
-
-       // get weapon info
-       entity e = Weapons_from(nix_weapon);
-
-       if(nix_nextchange != this.nix_lastchange_id) // this shall only be called once per round!
-       {
-               this.ammo_shells = this.ammo_nails = this.ammo_rockets = this.ammo_cells = this.ammo_plasma = this.ammo_fuel = 0;
-
-               if(this.items & IT_UNLIMITED_WEAPON_AMMO)
-               {
-                       switch(e.ammo_field)
-                       {
-                               case ammo_shells:  this.ammo_shells  = autocvar_g_pickup_shells_max;  break;
-                               case ammo_nails:   this.ammo_nails   = autocvar_g_pickup_nails_max;   break;
-                               case ammo_rockets: this.ammo_rockets = autocvar_g_pickup_rockets_max; break;
-                               case ammo_cells:   this.ammo_cells   = autocvar_g_pickup_cells_max;   break;
-                               case ammo_plasma:  this.ammo_plasma  = autocvar_g_pickup_plasma_max;   break;
-                               case ammo_fuel:    this.ammo_fuel    = autocvar_g_pickup_fuel_max;    break;
-                       }
-               }
-               else
-               {
-                       switch(e.ammo_field)
-                       {
-                               case ammo_shells:  this.ammo_shells  = autocvar_g_balance_nix_ammo_shells;  break;
-                               case ammo_nails:   this.ammo_nails   = autocvar_g_balance_nix_ammo_nails;   break;
-                               case ammo_rockets: this.ammo_rockets = autocvar_g_balance_nix_ammo_rockets; break;
-                               case ammo_cells:   this.ammo_cells   = autocvar_g_balance_nix_ammo_cells;   break;
-                               case ammo_plasma:  this.ammo_plasma  = autocvar_g_balance_nix_ammo_plasma;   break;
-                               case ammo_fuel:    this.ammo_fuel    = autocvar_g_balance_nix_ammo_fuel;    break;
-                       }
-               }
-
-               this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
-               if(dt >= 1 && dt <= 5)
-                       this.nix_lastinfotime = -42;
-               else
-                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
-
-               e.wr_resetplayer(e, this);
-
-               // all weapons must be fully loaded when we spawn
-               if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
-                       this.(weapon_load[nix_weapon]) = e.reloading_ammo;
-
-               // vortex too
-               if(WEP_CVAR(vortex, charge))
-               {
-                       if(WEP_CVAR_SEC(vortex, chargepool))
-                               this.vortex_chargepool_ammo = 1;
-                       this.vortex_charge = WEP_CVAR(vortex, charge_start);
-               }
-
-               // set last change info
-               this.nix_lastchange_id = nix_nextchange;
-       }
-       if(this.nix_lastinfotime != dt)
-       {
-               this.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
-               if(dt >= 1 && dt <= 5)
-                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt);
-       }
-
-       if(!(this.items & IT_UNLIMITED_WEAPON_AMMO) && time > this.nix_nextincr)
-       {
-               switch(e.ammo_field)
-               {
-                       case ammo_shells:  this.ammo_shells  += autocvar_g_balance_nix_ammoincr_shells;  break;
-                       case ammo_nails:   this.ammo_nails   += autocvar_g_balance_nix_ammoincr_nails;   break;
-                       case ammo_rockets: this.ammo_rockets += autocvar_g_balance_nix_ammoincr_rockets; break;
-                       case ammo_cells:   this.ammo_cells   += autocvar_g_balance_nix_ammoincr_cells;   break;
-                       case ammo_plasma:  this.ammo_plasma  += autocvar_g_balance_nix_ammoincr_plasma;   break;
-                       case ammo_fuel:    this.ammo_fuel    += autocvar_g_balance_nix_ammoincr_fuel;    break;
-               }
-
-               this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
-       }
-
-       this.weapons = '0 0 0';
-       if(g_nix_with_blaster)
-               this.weapons |= WEPSET(BLASTER);
-       this.weapons |= e.m_wepset;
-
-    Weapon w = Weapons_from(nix_weapon);
-       if(PS(this).m_switchweapon != w)
-               if(!client_hasweapon(this, PS(this).m_switchweapon, true, false))
-               {
-                       if(client_hasweapon(this, w, true, false))
-                               W_SwitchWeapon(this, w);
-               }
-}
-
-MUTATOR_HOOKFUNCTION(nix, ForbidThrowCurrentWeapon)
-{
-       return true; // no throwing in NIX
-}
-
-MUTATOR_HOOKFUNCTION(nix, BuildMutatorsString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":NIX");
-}
-
-MUTATOR_HOOKFUNCTION(nix, BuildMutatorsPrettyString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", NIX");
-}
-
-MUTATOR_HOOKFUNCTION(nix, FilterItem)
-{
-       entity item = M_ARGV(0, entity);
-
-       switch (item.items)
-       {
-               case ITEM_HealthSmall.m_itemid:
-               case ITEM_HealthMedium.m_itemid:
-               case ITEM_HealthLarge.m_itemid:
-               case ITEM_HealthMega.m_itemid:
-               case ITEM_ArmorSmall.m_itemid:
-               case ITEM_ArmorMedium.m_itemid:
-               case ITEM_ArmorLarge.m_itemid:
-               case ITEM_ArmorMega.m_itemid:
-                       if (autocvar_g_nix_with_healtharmor)
-                               return false;
-                       break;
-               case ITEM_Strength.m_itemid:
-               case ITEM_Shield.m_itemid:
-                       if (autocvar_g_nix_with_powerups)
-                               return false;
-                       break;
-       }
-
-       return true; // delete all other items
-}
-
-MUTATOR_HOOKFUNCTION(nix, OnEntityPreSpawn)
-{
-       entity ent = M_ARGV(0, entity);
-
-       if(ent.classname == "target_items") // items triggers cannot work in nix (as they change weapons/ammo)
-               return true;
-}
-
-MUTATOR_HOOKFUNCTION(nix, PlayerPreThink)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(!intermission_running)
-       if(!IS_DEAD(player))
-       if(IS_PLAYER(player))
-               NIX_GiveCurrentWeapon(player);
-}
-
-MUTATOR_HOOKFUNCTION(nix, PlayerSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       player.nix_lastchange_id = -1;
-       NIX_GiveCurrentWeapon(player); // overrides the weapons you got when spawning
-       player.items |= IT_UNLIMITED_SUPERWEAPONS;
-}
-
-MUTATOR_HOOKFUNCTION(nix, SetModname, CBC_ORDER_LAST)
-{
-       M_ARGV(0, string) = "NIX";
-}
-#endif
diff --git a/qcsrc/common/mutators/mutator/nix/sv_nix.qc b/qcsrc/common/mutators/mutator/nix/sv_nix.qc
new file mode 100644 (file)
index 0000000..97ed436
--- /dev/null
@@ -0,0 +1,288 @@
+#include "sv_nix.qh"
+
+int autocvar_g_balance_nix_ammo_cells;
+int autocvar_g_balance_nix_ammo_plasma;
+int autocvar_g_balance_nix_ammo_fuel;
+int autocvar_g_balance_nix_ammo_nails;
+int autocvar_g_balance_nix_ammo_rockets;
+int autocvar_g_balance_nix_ammo_shells;
+int autocvar_g_balance_nix_ammoincr_cells;
+int autocvar_g_balance_nix_ammoincr_plasma;
+int autocvar_g_balance_nix_ammoincr_fuel;
+int autocvar_g_balance_nix_ammoincr_nails;
+int autocvar_g_balance_nix_ammoincr_rockets;
+int autocvar_g_balance_nix_ammoincr_shells;
+float autocvar_g_balance_nix_incrtime;
+float autocvar_g_balance_nix_roundtime;
+bool autocvar_g_nix_with_healtharmor;
+bool autocvar_g_nix_with_blaster;
+bool autocvar_g_nix_with_powerups;
+int autocvar_g_pickup_cells_max;
+int autocvar_g_pickup_plasma_max;
+int autocvar_g_pickup_fuel_max;
+int autocvar_g_pickup_nails_max;
+int autocvar_g_pickup_rockets_max;
+int autocvar_g_pickup_shells_max;
+
+float g_nix_with_blaster;
+// WEAPONTODO
+int nix_weapon;
+float nix_nextchange;
+float nix_nextweapon;
+.float nix_lastchange_id;
+.float nix_lastinfotime;
+.float nix_nextincr;
+
+bool NIX_CanChooseWeapon(int wpn);
+
+REGISTER_MUTATOR(nix, cvar("g_nix") && !cvar("g_instagib") && !cvar("g_overkill"))
+{
+       MUTATOR_ONADD
+       {
+               g_nix_with_blaster = autocvar_g_nix_with_blaster;
+
+               nix_nextchange = 0;
+               nix_nextweapon = 0;
+
+               FOREACH(Weapons, it != WEP_Null && NIX_CanChooseWeapon(it.m_id), LAMBDA(it.wr_init(it)));
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // nothing to roll back
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               // as the PlayerSpawn hook will no longer run, NIX is turned off by this!
+               FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
+                       it.ammo_cells = start_ammo_cells;
+                       it.ammo_plasma = start_ammo_plasma;
+                       it.ammo_shells = start_ammo_shells;
+                       it.ammo_nails = start_ammo_nails;
+                       it.ammo_rockets = start_ammo_rockets;
+                       it.ammo_fuel = start_ammo_fuel;
+                       it.weapons = start_weapons;
+                       if(!client_hasweapon(it, PS(it).m_weapon, true, false))
+                               PS(it).m_switchweapon = w_getbestweapon(it);
+               });
+       }
+
+       return false;
+}
+
+bool NIX_CanChooseWeapon(int wpn)
+{
+       entity e = Weapons_from(wpn);
+       if (e == WEP_Null) return false; // skip dummies
+       if(g_weaponarena)
+       {
+               if(!(g_weaponarena_weapons & e.m_wepset))
+                       return false;
+       }
+       else
+       {
+               if(wpn == WEP_BLASTER.m_id && g_nix_with_blaster)
+                       return false;
+               if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
+                       return false;
+               if (!(e.spawnflags & WEP_FLAG_NORMAL))
+                       return false;
+       }
+       return true;
+}
+void NIX_ChooseNextWeapon()
+{
+       RandomSelection_Init();
+       FOREACH(Weapons, it != WEP_Null, LAMBDA(
+               if(NIX_CanChooseWeapon(it.m_id))
+                       RandomSelection_Add(NULL, it.m_id, string_null, 1, (it.m_id != nix_weapon));
+       ));
+       nix_nextweapon = RandomSelection_chosen_float;
+}
+
+void NIX_GiveCurrentWeapon(entity this)
+{
+       float dt;
+
+       if(!nix_nextweapon)
+               NIX_ChooseNextWeapon();
+
+       dt = ceil(nix_nextchange - time);
+
+       if(dt <= 0)
+       {
+               nix_weapon = nix_nextweapon;
+               nix_nextweapon = 0;
+               if (!nix_nextchange) // no round played yet?
+                       nix_nextchange = time; // start the first round now!
+               else
+                       nix_nextchange = time + autocvar_g_balance_nix_roundtime;
+               // Weapon w = Weapons_from(nix_weapon);
+               // w.wr_init(w); // forget it, too slow
+       }
+
+       // get weapon info
+       entity e = Weapons_from(nix_weapon);
+
+       if(nix_nextchange != this.nix_lastchange_id) // this shall only be called once per round!
+       {
+               this.ammo_shells = this.ammo_nails = this.ammo_rockets = this.ammo_cells = this.ammo_plasma = this.ammo_fuel = 0;
+
+               if(this.items & IT_UNLIMITED_WEAPON_AMMO)
+               {
+                       switch(e.ammo_field)
+                       {
+                               case ammo_shells:  this.ammo_shells  = autocvar_g_pickup_shells_max;  break;
+                               case ammo_nails:   this.ammo_nails   = autocvar_g_pickup_nails_max;   break;
+                               case ammo_rockets: this.ammo_rockets = autocvar_g_pickup_rockets_max; break;
+                               case ammo_cells:   this.ammo_cells   = autocvar_g_pickup_cells_max;   break;
+                               case ammo_plasma:  this.ammo_plasma  = autocvar_g_pickup_plasma_max;   break;
+                               case ammo_fuel:    this.ammo_fuel    = autocvar_g_pickup_fuel_max;    break;
+                       }
+               }
+               else
+               {
+                       switch(e.ammo_field)
+                       {
+                               case ammo_shells:  this.ammo_shells  = autocvar_g_balance_nix_ammo_shells;  break;
+                               case ammo_nails:   this.ammo_nails   = autocvar_g_balance_nix_ammo_nails;   break;
+                               case ammo_rockets: this.ammo_rockets = autocvar_g_balance_nix_ammo_rockets; break;
+                               case ammo_cells:   this.ammo_cells   = autocvar_g_balance_nix_ammo_cells;   break;
+                               case ammo_plasma:  this.ammo_plasma  = autocvar_g_balance_nix_ammo_plasma;   break;
+                               case ammo_fuel:    this.ammo_fuel    = autocvar_g_balance_nix_ammo_fuel;    break;
+                       }
+               }
+
+               this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
+               if(dt >= 1 && dt <= 5)
+                       this.nix_lastinfotime = -42;
+               else
+                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
+
+               e.wr_resetplayer(e, this);
+
+               // all weapons must be fully loaded when we spawn
+               if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
+                       this.(weapon_load[nix_weapon]) = e.reloading_ammo;
+
+               // vortex too
+               if(WEP_CVAR(vortex, charge))
+               {
+                       if(WEP_CVAR_SEC(vortex, chargepool))
+                               this.vortex_chargepool_ammo = 1;
+                       this.vortex_charge = WEP_CVAR(vortex, charge_start);
+               }
+
+               // set last change info
+               this.nix_lastchange_id = nix_nextchange;
+       }
+       if(this.nix_lastinfotime != dt)
+       {
+               this.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
+               if(dt >= 1 && dt <= 5)
+                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt);
+       }
+
+       if(!(this.items & IT_UNLIMITED_WEAPON_AMMO) && time > this.nix_nextincr)
+       {
+               switch(e.ammo_field)
+               {
+                       case ammo_shells:  this.ammo_shells  += autocvar_g_balance_nix_ammoincr_shells;  break;
+                       case ammo_nails:   this.ammo_nails   += autocvar_g_balance_nix_ammoincr_nails;   break;
+                       case ammo_rockets: this.ammo_rockets += autocvar_g_balance_nix_ammoincr_rockets; break;
+                       case ammo_cells:   this.ammo_cells   += autocvar_g_balance_nix_ammoincr_cells;   break;
+                       case ammo_plasma:  this.ammo_plasma  += autocvar_g_balance_nix_ammoincr_plasma;   break;
+                       case ammo_fuel:    this.ammo_fuel    += autocvar_g_balance_nix_ammoincr_fuel;    break;
+               }
+
+               this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
+       }
+
+       this.weapons = '0 0 0';
+       if(g_nix_with_blaster)
+               this.weapons |= WEPSET(BLASTER);
+       this.weapons |= e.m_wepset;
+
+    Weapon w = Weapons_from(nix_weapon);
+       if(PS(this).m_switchweapon != w)
+               if(!client_hasweapon(this, PS(this).m_switchweapon, true, false))
+               {
+                       if(client_hasweapon(this, w, true, false))
+                               W_SwitchWeapon(this, w);
+               }
+}
+
+MUTATOR_HOOKFUNCTION(nix, ForbidThrowCurrentWeapon)
+{
+       return true; // no throwing in NIX
+}
+
+MUTATOR_HOOKFUNCTION(nix, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":NIX");
+}
+
+MUTATOR_HOOKFUNCTION(nix, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", NIX");
+}
+
+MUTATOR_HOOKFUNCTION(nix, FilterItem)
+{
+       entity item = M_ARGV(0, entity);
+
+       switch (item.items)
+       {
+               case ITEM_HealthSmall.m_itemid:
+               case ITEM_HealthMedium.m_itemid:
+               case ITEM_HealthLarge.m_itemid:
+               case ITEM_HealthMega.m_itemid:
+               case ITEM_ArmorSmall.m_itemid:
+               case ITEM_ArmorMedium.m_itemid:
+               case ITEM_ArmorLarge.m_itemid:
+               case ITEM_ArmorMega.m_itemid:
+                       if (autocvar_g_nix_with_healtharmor)
+                               return false;
+                       break;
+               case ITEM_Strength.m_itemid:
+               case ITEM_Shield.m_itemid:
+                       if (autocvar_g_nix_with_powerups)
+                               return false;
+                       break;
+       }
+
+       return true; // delete all other items
+}
+
+MUTATOR_HOOKFUNCTION(nix, OnEntityPreSpawn)
+{
+       entity ent = M_ARGV(0, entity);
+
+       if(ent.classname == "target_items") // items triggers cannot work in nix (as they change weapons/ammo)
+               return true;
+}
+
+MUTATOR_HOOKFUNCTION(nix, PlayerPreThink)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(!intermission_running)
+       if(!IS_DEAD(player))
+       if(IS_PLAYER(player))
+               NIX_GiveCurrentWeapon(player);
+}
+
+MUTATOR_HOOKFUNCTION(nix, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       player.nix_lastchange_id = -1;
+       NIX_GiveCurrentWeapon(player); // overrides the weapons you got when spawning
+       player.items |= IT_UNLIMITED_SUPERWEAPONS;
+}
+
+MUTATOR_HOOKFUNCTION(nix, SetModname, CBC_ORDER_LAST)
+{
+       M_ARGV(0, string) = "NIX";
+}
diff --git a/qcsrc/common/mutators/mutator/nix/sv_nix.qh b/qcsrc/common/mutators/mutator/nix/sv_nix.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 5b42a4dd11fec6420d530a25a3096edb5b334f5e..0552173c1a0874c8c8ca6765ac0a922ff60ff01b 100644 (file)
@@ -1,4 +1,10 @@
 // generated file; do not modify
 #include <common/mutators/mutator/overkill/hmg.qc>
 #include <common/mutators/mutator/overkill/overkill.qc>
+#ifdef CSQC
+    #include <common/mutators/mutator/overkill/cl_overkill.qc>
+#endif
+#ifdef SVQC
+    #include <common/mutators/mutator/overkill/sv_overkill.qc>
+#endif
 #include <common/mutators/mutator/overkill/rpc.qc>
index 7a46694446e351814ae7ca31eee7091146cc2901..13e42431b32ebb3a28c11504a38fb822e69d7640 100644 (file)
@@ -1,4 +1,10 @@
 // generated file; do not modify
 #include <common/mutators/mutator/overkill/hmg.qh>
 #include <common/mutators/mutator/overkill/overkill.qh>
+#ifdef CSQC
+    #include <common/mutators/mutator/overkill/cl_overkill.qh>
+#endif
+#ifdef SVQC
+    #include <common/mutators/mutator/overkill/sv_overkill.qh>
+#endif
 #include <common/mutators/mutator/overkill/rpc.qh>
diff --git a/qcsrc/common/mutators/mutator/overkill/cl_overkill.qc b/qcsrc/common/mutators/mutator/overkill/cl_overkill.qc
new file mode 100644 (file)
index 0000000..eb21953
--- /dev/null
@@ -0,0 +1,11 @@
+#include "cl_overkill.qh"
+
+REGISTER_MUTATOR(ok, false)
+{
+       MUTATOR_ONADD {
+               cvar_settemp("g_overkill", "1");
+               WEP_SHOTGUN.mdl = "ok_shotgun";
+               WEP_MACHINEGUN.mdl = "ok_mg";
+               WEP_VORTEX.mdl = "ok_sniper";
+       }
+}
diff --git a/qcsrc/common/mutators/mutator/overkill/cl_overkill.qh b/qcsrc/common/mutators/mutator/overkill/cl_overkill.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 1512992c250f1e75b508fc0e3eb62ea07afdef59..024fdb1cc768397f28409097e9f2e5166fa57b0a 100644 (file)
@@ -1,47 +1,5 @@
-#ifndef IMPLEMENTATION
-CLASS(HeavyMachineGun, Weapon)
-/* ammotype  */ ATTRIB(HeavyMachineGun, ammo_field, .int, ammo_nails);
-/* impulse   */ ATTRIB(HeavyMachineGun, impulse, int, 3);
-/* flags     */ ATTRIB(HeavyMachineGun, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_SUPERWEAPON);
-/* rating    */ ATTRIB(HeavyMachineGun, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
-/* color     */ ATTRIB(HeavyMachineGun, wpcolor, vector, '0.5 0.5 0');
-/* modelname */ ATTRIB(HeavyMachineGun, mdl, string, "ok_hmg");
-#ifndef MENUQC
-/* model     */ ATTRIB(HeavyMachineGun, m_model, Model, MDL_HMG_ITEM);
-#endif
-/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair, string, "gfx/crosshairuzi");
-/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair_size, float, 0.6);
-/* wepimg    */ ATTRIB(HeavyMachineGun, model2, string, "weaponhmg");
-/* refname   */ ATTRIB(HeavyMachineGun, netname, string, "hmg");
-/* wepname   */ ATTRIB(HeavyMachineGun, m_name, string, _("Heavy Machine Gun"));
-
-#define X(BEGIN, P, END, class, prefix) \
-       BEGIN(class) \
-               P(class, prefix, ammo, float, NONE) \
-               P(class, prefix, damage, float, NONE) \
-               P(class, prefix, force, float, NONE) \
-               P(class, prefix, refire, float, NONE) \
-               P(class, prefix, reload_ammo, float, NONE) \
-               P(class, prefix, reload_time, float, NONE) \
-               P(class, prefix, solidpenetration, float, NONE) \
-               P(class, prefix, spread_add, float, NONE) \
-               P(class, prefix, spread_max, float, NONE) \
-               P(class, prefix, spread_min, float, NONE) \
-               P(class, prefix, switchdelay_drop, float, NONE) \
-               P(class, prefix, switchdelay_raise, float, NONE) \
-               P(class, prefix, weaponreplace, string, NONE) \
-               P(class, prefix, weaponstartoverride, float, NONE) \
-               P(class, prefix, weaponstart, float, NONE) \
-               P(class, prefix, weaponthrowable, float, NONE) \
-    END()
-    W_PROPS(X, HeavyMachineGun, hmg)
-#undef X
-
-ENDCLASS(HeavyMachineGun)
-REGISTER_WEAPON(HMG, hmg, NEW(HeavyMachineGun));
+#include "hmg.qh"
 
-#endif
-#ifdef IMPLEMENTATION
 #ifdef SVQC
 
 REGISTER_MUTATOR(hmg_nadesupport, true);
@@ -174,4 +132,3 @@ METHOD(HeavyMachineGun, wr_impacteffect, void(entity thiswep, entity actor))
 }
 
 #endif
-#endif
diff --git a/qcsrc/common/mutators/mutator/overkill/hmg.qh b/qcsrc/common/mutators/mutator/overkill/hmg.qh
new file mode 100644 (file)
index 0000000..7219fd1
--- /dev/null
@@ -0,0 +1,42 @@
+#pragma once
+
+CLASS(HeavyMachineGun, Weapon)
+/* ammotype  */ ATTRIB(HeavyMachineGun, ammo_field, .int, ammo_nails);
+/* impulse   */ ATTRIB(HeavyMachineGun, impulse, int, 3);
+/* flags     */ ATTRIB(HeavyMachineGun, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_SUPERWEAPON);
+/* rating    */ ATTRIB(HeavyMachineGun, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
+/* color     */ ATTRIB(HeavyMachineGun, wpcolor, vector, '0.5 0.5 0');
+/* modelname */ ATTRIB(HeavyMachineGun, mdl, string, "ok_hmg");
+#ifdef GAMEQC
+/* model     */ ATTRIB(HeavyMachineGun, m_model, Model, MDL_HMG_ITEM);
+#endif
+/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair, string, "gfx/crosshairuzi");
+/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair_size, float, 0.6);
+/* wepimg    */ ATTRIB(HeavyMachineGun, model2, string, "weaponhmg");
+/* refname   */ ATTRIB(HeavyMachineGun, netname, string, "hmg");
+/* wepname   */ ATTRIB(HeavyMachineGun, m_name, string, _("Heavy Machine Gun"));
+
+#define X(BEGIN, P, END, class, prefix) \
+       BEGIN(class) \
+               P(class, prefix, ammo, float, NONE) \
+               P(class, prefix, damage, float, NONE) \
+               P(class, prefix, force, float, NONE) \
+               P(class, prefix, refire, float, NONE) \
+               P(class, prefix, reload_ammo, float, NONE) \
+               P(class, prefix, reload_time, float, NONE) \
+               P(class, prefix, solidpenetration, float, NONE) \
+               P(class, prefix, spread_add, float, NONE) \
+               P(class, prefix, spread_max, float, NONE) \
+               P(class, prefix, spread_min, float, NONE) \
+               P(class, prefix, switchdelay_drop, float, NONE) \
+               P(class, prefix, switchdelay_raise, float, NONE) \
+               P(class, prefix, weaponreplace, string, NONE) \
+               P(class, prefix, weaponstartoverride, float, NONE) \
+               P(class, prefix, weaponstart, float, NONE) \
+               P(class, prefix, weaponthrowable, float, NONE) \
+    END()
+    W_PROPS(X, HeavyMachineGun, hmg)
+#undef X
+
+ENDCLASS(HeavyMachineGun)
+REGISTER_WEAPON(HMG, hmg, NEW(HeavyMachineGun));
diff --git a/qcsrc/common/mutators/mutator/overkill/module.inc b/qcsrc/common/mutators/mutator/overkill/module.inc
deleted file mode 100644 (file)
index a7acff5..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "hmg.qc"
-#include "rpc.qc"
-
-#ifdef SVQC
-       #include "overkill.qc"
-#endif
-#ifdef CSQC
-       #ifdef IMPLEMENTATION
-               REGISTER_MUTATOR(ok, false)
-               {
-                       MUTATOR_ONADD {
-                               cvar_settemp("g_overkill", "1");
-                               WEP_SHOTGUN.mdl = "ok_shotgun";
-                               WEP_MACHINEGUN.mdl = "ok_mg";
-                               WEP_VORTEX.mdl = "ok_sniper";
-                       }
-               }
-       #endif
-#endif
index f49fdc11b4a2901a3038257ecd8b9cf2f7990060..3cb64ce9234761703a1876d0310c873fa2bbe5e8 100644 (file)
@@ -1,410 +1 @@
-#ifdef IMPLEMENTATION
-bool autocvar_g_overkill_powerups_replace;
-float autocvar_g_overkill_superguns_respawn_time;
-bool autocvar_g_overkill_100h_anyway;
-bool autocvar_g_overkill_100a_anyway;
-bool autocvar_g_overkill_ammo_charge;
-float autocvar_g_overkill_ammo_charge_notice;
-float autocvar_g_overkill_ammo_charge_limit;
-
-.vector ok_deathloc;
-.float ok_spawnsys_timer;
-.float ok_lastwep;
-.float ok_item;
-
-.float ok_notice_time;
-.float ammo_charge[Weapons_MAX];
-.float ok_use_ammocharge = _STAT(OK_AMMO_CHARGE);
-.float ok_ammo_charge = _STAT(OK_AMMO_CHARGEPOOL);
-
-.float ok_pauseregen_finished;
-
-void(entity ent, float wep) ok_DecreaseCharge;
-
-void ok_Initialize();
-
-REGISTER_MUTATOR(ok, cvar("g_overkill") && !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
-{
-       MUTATOR_ONADD
-       {
-               ok_Initialize();
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               WEP_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-               WEP_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ok, W_DecreaseAmmo)
-{
-       entity actor = M_ARGV(0, entity);
-       if (actor.ok_use_ammocharge)
-       {
-               ok_DecreaseCharge(actor, PS(actor).m_weapon.m_id);
-               return true;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ok, W_Reload)
-{
-       entity actor = M_ARGV(0, entity);
-       return actor.ok_use_ammocharge;
-}
-
-void W_Blaster_Attack(entity, .entity, float, float, float, float, float, float, float, float, float, float);
-spawnfunc(weapon_hmg);
-spawnfunc(weapon_rpc);
-
-void ok_DecreaseCharge(entity ent, int wep)
-{
-       if(!ent.ok_use_ammocharge) return;
-
-       entity wepent = Weapons_from(wep);
-
-       if (wepent == WEP_Null) return;  // dummy
-
-       ent.ammo_charge[wep] -= max(0, cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
-}
-
-void ok_IncreaseCharge(entity ent, int wep)
-{
-       entity wepent = Weapons_from(wep);
-
-       if (wepent == WEP_Null) return;  // dummy
-
-       if(ent.ok_use_ammocharge)
-       if(!PHYS_INPUT_BUTTON_ATCK(ent)) // not while attacking?
-               ent.ammo_charge[wep] = min(autocvar_g_overkill_ammo_charge_limit, ent.ammo_charge[wep] + cvar(sprintf("g_overkill_ammo_charge_rate_%s", wepent.netname)) * frametime / W_TICSPERFRAME);
-}
-
-float ok_CheckWeaponCharge(entity ent, int wep)
-{
-       if(!ent.ok_use_ammocharge) return true;
-
-       entity wepent = Weapons_from(wep);
-
-       if(wepent == WEP_Null) return false;  // dummy
-
-       return (ent.ammo_charge[wep] >= cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerDamage_Calculate, CBC_ORDER_LAST)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-       float frag_deathtype = M_ARGV(3, float);
-
-       if(IS_PLAYER(frag_attacker) && IS_PLAYER(frag_target))
-       if(DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
-       {
-               if(frag_attacker != frag_target)
-               if(frag_target.health > 0)
-               if(STAT(FROZEN, frag_target) == 0)
-               if(!IS_DEAD(frag_target))
-               {
-                       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE);
-                       M_ARGV(6, vector) = '0 0 0';
-               }
-
-               M_ARGV(4, float) = 0;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerDamage_SplitHealthArmor)
-{
-       entity frag_target = M_ARGV(2, entity);
-       float damage_take = M_ARGV(4, float);
-
-       if(damage_take)
-               frag_target.ok_pauseregen_finished = max(frag_target.ok_pauseregen_finished, time + 2);
-}
-
-void ok_DropItem(entity this, entity targ)
-{
-       entity e = new(droppedweapon); // hax
-       e.ok_item = true;
-       e.noalign = true;
-       e.pickup_anyway = true;
-       e.spawnfunc_checked = true;
-       spawnfunc_item_armor_small(e);
-       if (!wasfreed(e)) { // might have been blocked by a mutator
-        set_movetype(e, MOVETYPE_TOSS);
-        e.gravity = 1;
-        e.reset = SUB_Remove;
-        setorigin(e, this.origin + '0 0 32');
-        e.velocity = '0 0 200' + normalize(targ.origin - this.origin) * 500;
-        SUB_SetFade(e, time + 5, 1);
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerDies)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-
-       entity targ = ((frag_attacker) ? frag_attacker : frag_target);
-
-       ok_DropItem(frag_target, targ);
-
-       frag_target.ok_lastwep = PS(frag_target).m_switchweapon.m_id;
-}
-
-MUTATOR_HOOKFUNCTION(ok, MonsterDropItem)
-{
-       entity mon = M_ARGV(0, entity);
-       entity olditem = M_ARGV(1, entity);
-       entity frag_attacker = M_ARGV(2, entity);
-
-       delete(olditem);
-
-       M_ARGV(1, entity) = NULL;
-
-       ok_DropItem(mon, frag_attacker);
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerRegen)
-{
-       entity player = M_ARGV(0, entity);
-
-       // overkill's values are different, so use custom regen
-       if(!STAT(FROZEN, player))
-       {
-               player.armorvalue = CalcRotRegen(player.armorvalue, autocvar_g_balance_armor_regenstable, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear,
-                       1 * frametime * (time > player.ok_pauseregen_finished), 0, 0, 1, 1 * frametime * (time > player.pauserotarmor_finished), autocvar_g_balance_armor_limit);
-               player.health = CalcRotRegen(player.health, autocvar_g_balance_health_regenstable, 0, 100, 1 * frametime * (time > player.ok_pauseregen_finished), 200, 0,
-                       autocvar_g_balance_health_rotlinear, 1 * frametime * (time > player.pauserothealth_finished), autocvar_g_balance_health_limit);
-
-               float minf, maxf, limitf;
-
-               maxf = autocvar_g_balance_fuel_rotstable;
-               minf = autocvar_g_balance_fuel_regenstable;
-               limitf = autocvar_g_balance_fuel_limit;
-
-               player.ammo_fuel = CalcRotRegen(player.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear,
-                       frametime * (time > player.pauseregen_finished) * ((player.items & ITEM_JetpackRegen.m_itemid) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > player.pauserotfuel_finished), limitf);
-       }
-       return true; // return true anyway, as frozen uses no regen
-}
-
-MUTATOR_HOOKFUNCTION(ok, ForbidThrowCurrentWeapon)
-{
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerPreThink)
-{
-       if(intermission_running || gameover)
-               return;
-
-       entity player = M_ARGV(0, entity);
-
-       if(IS_DEAD(player) || !IS_PLAYER(player) || STAT(FROZEN, player))
-               return;
-
-       if(player.ok_lastwep)
-       {
-               Weapon newwep = Weapons_from(player.ok_lastwep);
-               if(player.ok_lastwep == WEP_HMG.m_id)
-                       newwep = WEP_MACHINEGUN;
-               if(player.ok_lastwep == WEP_RPC.m_id)
-                       newwep = WEP_VORTEX;
-               PS(player).m_switchweapon = newwep;
-               player.ok_lastwep = 0;
-       }
-
-       ok_IncreaseCharge(player, PS(player).m_weapon.m_id);
-
-       if(PHYS_INPUT_BUTTON_ATCK2(player))
-       if(!forbidWeaponUse(player) || player.weapon_blocked) // allow if weapon is blocked
-       if(time >= player.jump_interval)
-       {
-               player.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor(player);
-               makevectors(player.v_angle);
-
-               Weapon oldwep = PS(player).m_weapon;
-               PS(player).m_weapon = WEP_BLASTER;
-               W_Blaster_Attack(
-                       player,
-                       weaponentities[0], // TODO: unhardcode
-                       WEP_BLASTER.m_id | HITTYPE_SECONDARY,
-                       WEP_CVAR_SEC(vaporizer, shotangle),
-                       WEP_CVAR_SEC(vaporizer, damage),
-                       WEP_CVAR_SEC(vaporizer, edgedamage),
-                       WEP_CVAR_SEC(vaporizer, radius),
-                       WEP_CVAR_SEC(vaporizer, force),
-                       WEP_CVAR_SEC(vaporizer, speed),
-                       WEP_CVAR_SEC(vaporizer, spread),
-                       WEP_CVAR_SEC(vaporizer, delay),
-                       WEP_CVAR_SEC(vaporizer, lifetime)
-               );
-               PS(player).m_weapon = oldwep;
-       }
-
-       player.weapon_blocked = false;
-
-       player.ok_ammo_charge = player.ammo_charge[PS(player).m_weapon.m_id];
-
-       if(player.ok_use_ammocharge)
-       if(!ok_CheckWeaponCharge(player, PS(player).m_weapon.m_id))
-       {
-               if(autocvar_g_overkill_ammo_charge_notice && time > player.ok_notice_time && PHYS_INPUT_BUTTON_ATCK(player) && IS_REAL_CLIENT(player) && PS(player).m_weapon == PS(player).m_switchweapon)
-               {
-                       //Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_OVERKILL_CHARGE);
-                       player.ok_notice_time = time + 2;
-                       play2(player, SND(DRYFIRE));
-               }
-               Weapon wpn = PS(player).m_weapon;
-               .entity weaponentity = weaponentities[0]; // TODO: unhardcode
-               if(player.(weaponentity).state != WS_CLEAR)
-                       w_ready(wpn, player, weaponentity, PHYS_INPUT_BUTTON_ATCK(player) | (PHYS_INPUT_BUTTON_ATCK2(player) << 1));
-
-               player.weapon_blocked = true;
-       }
-
-       PHYS_INPUT_BUTTON_ATCK2(player) = false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(autocvar_g_overkill_ammo_charge)
-       {
-               FOREACH(Weapons, it != WEP_Null, LAMBDA(player.ammo_charge[it.m_id] = autocvar_g_overkill_ammo_charge_limit));
-
-               player.ok_use_ammocharge = 1;
-               player.ok_notice_time = time;
-       }
-       else
-               player.ok_use_ammocharge = 0;
-
-       // if player changed their weapon while dead, don't switch to their death weapon
-       if(player.impulse)
-               player.ok_lastwep = 0;
-
-       player.ok_pauseregen_finished = time + 2;
-}
-
-void self_spawnfunc_weapon_hmg(entity this) { spawnfunc_weapon_hmg(this); }
-void self_spawnfunc_weapon_rpc(entity this) { spawnfunc_weapon_rpc(this); }
-
-MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
-{
-       entity ent = M_ARGV(0, entity);
-
-       if(autocvar_g_powerups)
-       if(autocvar_g_overkill_powerups_replace)
-       {
-               if(ent.classname == "item_strength")
-               {
-                       entity wep = new(weapon_hmg);
-                       setorigin(wep, ent.origin);
-                       setmodel(wep, MDL_OK_HMG);
-                       wep.ok_item = true;
-                       wep.noalign = ent.noalign;
-                       wep.cnt = ent.cnt;
-                       wep.team = ent.team;
-                       wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
-                       wep.pickup_anyway = true;
-                       wep.spawnfunc_checked = true;
-                       setthink(wep, self_spawnfunc_weapon_hmg);
-                       wep.nextthink = time + 0.1;
-                       return true;
-               }
-
-               if(ent.classname == "item_invincible")
-               {
-                       entity wep = new(weapon_rpc);
-                       setorigin(wep, ent.origin);
-                       setmodel(wep, MDL_OK_RPC);
-                       wep.ok_item = true;
-                       wep.noalign = ent.noalign;
-                       wep.cnt = ent.cnt;
-                       wep.team = ent.team;
-                       wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
-                       wep.pickup_anyway = true;
-                       wep.spawnfunc_checked = true;
-                       setthink(wep, self_spawnfunc_weapon_rpc);
-                       wep.nextthink = time + 0.1;
-                       return true;
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ok, FilterItem)
-{
-       entity item = M_ARGV(0, entity);
-
-       if(item.ok_item)
-               return;
-
-       switch(item.items)
-       {
-               case ITEM_HealthMega.m_itemid: return !(autocvar_g_overkill_100h_anyway);
-               case ITEM_ArmorMega.m_itemid: return !(autocvar_g_overkill_100a_anyway);
-       }
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ok, SpectateCopy)
-{
-       entity spectatee = M_ARGV(0, entity);
-       entity client = M_ARGV(1, entity);
-
-       client.ammo_charge[PS(client).m_weapon.m_id] = spectatee.ammo_charge[PS(spectatee).m_weapon.m_id];
-       client.ok_use_ammocharge = spectatee.ok_use_ammocharge;
-}
-
-MUTATOR_HOOKFUNCTION(ok, SetStartItems)
-{
-       WepSet ok_start_items = (WEPSET(MACHINEGUN) | WEPSET(VORTEX) | WEPSET(SHOTGUN));
-
-       if(WEP_RPC.weaponstart > 0) { ok_start_items |= WEPSET(RPC); }
-       if(WEP_HMG.weaponstart > 0) { ok_start_items |= WEPSET(HMG); }
-
-       start_items |= IT_UNLIMITED_WEAPON_AMMO;
-       start_weapons = warmup_start_weapons = ok_start_items;
-}
-
-MUTATOR_HOOKFUNCTION(ok, BuildMutatorsString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":OK");
-}
-
-MUTATOR_HOOKFUNCTION(ok, BuildMutatorsPrettyString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Overkill");
-}
-
-MUTATOR_HOOKFUNCTION(ok, SetModname)
-{
-       M_ARGV(0, string) = "Overkill";
-       return true;
-}
-
-void ok_SetCvars()
-{
-       // hack to force overkill playermodels
-       cvar_settemp("sv_defaultcharacter", "1");
-       cvar_settemp("sv_defaultplayermodel", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
-       cvar_settemp("sv_defaultplayermodel_red", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm");
-       cvar_settemp("sv_defaultplayermodel_blue", "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
-}
-
-void ok_Initialize()
-{
-       ok_SetCvars();
-
-       precache_all_playermodels("models/ok_player/*.dpm");
-
-       WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-       WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-
-       WEP_SHOTGUN.mdl = "ok_shotgun";
-       WEP_MACHINEGUN.mdl = "ok_mg";
-       WEP_VORTEX.mdl = "ok_sniper";
-}
-#endif
+#include "overkill.qh"
diff --git a/qcsrc/common/mutators/mutator/overkill/overkill.qh b/qcsrc/common/mutators/mutator/overkill/overkill.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index f9be2ad9f58c4dd41e660e8e775954cfad0c8777..122bdfc12c49bb43c89c6bb522352d18e1382b2e 100644 (file)
@@ -1,52 +1,5 @@
-#ifndef IMPLEMENTATION
-CLASS(RocketPropelledChainsaw, Weapon)
-/* ammotype  */ ATTRIB(RocketPropelledChainsaw, ammo_field, .int, ammo_rockets);
-/* impulse   */ ATTRIB(RocketPropelledChainsaw, impulse, int, 7);
-/* flags     */ ATTRIB(RocketPropelledChainsaw, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH | WEP_FLAG_SUPERWEAPON);
-/* rating    */ ATTRIB(RocketPropelledChainsaw, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
-/* color     */ ATTRIB(RocketPropelledChainsaw, wpcolor, vector, '0.5 0.5 0');
-/* modelname */ ATTRIB(RocketPropelledChainsaw, mdl, string, "ok_rl");
-#ifndef MENUQC
-/* model     */ ATTRIB(RocketPropelledChainsaw, m_model, Model, MDL_RPC_ITEM);
-#endif
-/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair, string, "gfx/crosshairrocketlauncher");
-/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair_size, float, 0.6);
-/* wepimg    */ ATTRIB(RocketPropelledChainsaw, model2, string, "weaponrpc");
-/* refname   */ ATTRIB(RocketPropelledChainsaw, netname, string, "rpc");
-/* wepname   */ ATTRIB(RocketPropelledChainsaw, m_name, string, _("Rocket Propelled Chainsaw"));
-
-#define X(BEGIN, P, END, class, prefix) \
-       BEGIN(class) \
-               P(class, prefix, ammo, float, NONE) \
-               P(class, prefix, animtime, float, NONE) \
-               P(class, prefix, damage2, float, NONE) \
-               P(class, prefix, damageforcescale, float, NONE) \
-               P(class, prefix, damage, float, NONE) \
-               P(class, prefix, edgedamage, float, NONE) \
-               P(class, prefix, force, float, NONE) \
-               P(class, prefix, health, float, NONE) \
-               P(class, prefix, lifetime, float, NONE) \
-               P(class, prefix, radius, float, NONE) \
-               P(class, prefix, refire, float, NONE) \
-               P(class, prefix, reload_ammo, float, NONE) \
-        P(class, prefix, reload_time, float, NONE) \
-               P(class, prefix, speedaccel, float, NONE) \
-               P(class, prefix, speed, float, NONE) \
-        P(class, prefix, switchdelay_drop, float, NONE) \
-        P(class, prefix, switchdelay_raise, float, NONE) \
-        P(class, prefix, weaponreplace, string, NONE) \
-        P(class, prefix, weaponstartoverride, float, NONE) \
-        P(class, prefix, weaponstart, float, NONE) \
-        P(class, prefix, weaponthrowable, float, NONE) \
-    END()
-    W_PROPS(X, RocketPropelledChainsaw, rpc)
-#undef X
-
-ENDCLASS(RocketPropelledChainsaw)
-REGISTER_WEAPON(RPC, rpc, NEW(RocketPropelledChainsaw));
+#include "rpc.qh"
 
-#endif
-#ifdef IMPLEMENTATION
 #ifdef SVQC
 spawnfunc(weapon_rpc) { weapon_defaultspawnfunc(this, WEP_RPC); }
 
@@ -144,6 +97,7 @@ void W_RocketPropelledChainsaw_Attack (Weapon thiswep, entity actor, .entity wea
        missile.nextthink = time;
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
+       IL_PUSH(g_bot_dodge, missile);
 
        CSQCProjectile(missile, true, PROJECTILE_RPC, false);
 
@@ -232,4 +186,3 @@ METHOD(RocketPropelledChainsaw, wr_impacteffect, void(entity thiswep, entity act
 }
 
 #endif
-#endif
diff --git a/qcsrc/common/mutators/mutator/overkill/rpc.qh b/qcsrc/common/mutators/mutator/overkill/rpc.qh
new file mode 100644 (file)
index 0000000..535fa55
--- /dev/null
@@ -0,0 +1,47 @@
+#pragma once
+
+CLASS(RocketPropelledChainsaw, Weapon)
+/* ammotype  */ ATTRIB(RocketPropelledChainsaw, ammo_field, .int, ammo_rockets);
+/* impulse   */ ATTRIB(RocketPropelledChainsaw, impulse, int, 7);
+/* flags     */ ATTRIB(RocketPropelledChainsaw, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH | WEP_FLAG_SUPERWEAPON);
+/* rating    */ ATTRIB(RocketPropelledChainsaw, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
+/* color     */ ATTRIB(RocketPropelledChainsaw, wpcolor, vector, '0.5 0.5 0');
+/* modelname */ ATTRIB(RocketPropelledChainsaw, mdl, string, "ok_rl");
+#ifdef GAMEQC
+/* model     */ ATTRIB(RocketPropelledChainsaw, m_model, Model, MDL_RPC_ITEM);
+#endif
+/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair, string, "gfx/crosshairrocketlauncher");
+/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair_size, float, 0.6);
+/* wepimg    */ ATTRIB(RocketPropelledChainsaw, model2, string, "weaponrpc");
+/* refname   */ ATTRIB(RocketPropelledChainsaw, netname, string, "rpc");
+/* wepname   */ ATTRIB(RocketPropelledChainsaw, m_name, string, _("Rocket Propelled Chainsaw"));
+
+#define X(BEGIN, P, END, class, prefix) \
+       BEGIN(class) \
+               P(class, prefix, ammo, float, NONE) \
+               P(class, prefix, animtime, float, NONE) \
+               P(class, prefix, damage2, float, NONE) \
+               P(class, prefix, damageforcescale, float, NONE) \
+               P(class, prefix, damage, float, NONE) \
+               P(class, prefix, edgedamage, float, NONE) \
+               P(class, prefix, force, float, NONE) \
+               P(class, prefix, health, float, NONE) \
+               P(class, prefix, lifetime, float, NONE) \
+               P(class, prefix, radius, float, NONE) \
+               P(class, prefix, refire, float, NONE) \
+               P(class, prefix, reload_ammo, float, NONE) \
+        P(class, prefix, reload_time, float, NONE) \
+               P(class, prefix, speedaccel, float, NONE) \
+               P(class, prefix, speed, float, NONE) \
+        P(class, prefix, switchdelay_drop, float, NONE) \
+        P(class, prefix, switchdelay_raise, float, NONE) \
+        P(class, prefix, weaponreplace, string, NONE) \
+        P(class, prefix, weaponstartoverride, float, NONE) \
+        P(class, prefix, weaponstart, float, NONE) \
+        P(class, prefix, weaponthrowable, float, NONE) \
+    END()
+    W_PROPS(X, RocketPropelledChainsaw, rpc)
+#undef X
+
+ENDCLASS(RocketPropelledChainsaw)
+REGISTER_WEAPON(RPC, rpc, NEW(RocketPropelledChainsaw));
diff --git a/qcsrc/common/mutators/mutator/overkill/sv_overkill.qc b/qcsrc/common/mutators/mutator/overkill/sv_overkill.qc
new file mode 100644 (file)
index 0000000..ea7ed95
--- /dev/null
@@ -0,0 +1,413 @@
+#include "sv_overkill.qh"
+
+#include "hmg.qh"
+#include "rpc.qh"
+
+bool autocvar_g_overkill_powerups_replace;
+float autocvar_g_overkill_superguns_respawn_time;
+bool autocvar_g_overkill_100h_anyway;
+bool autocvar_g_overkill_100a_anyway;
+bool autocvar_g_overkill_ammo_charge;
+float autocvar_g_overkill_ammo_charge_notice;
+float autocvar_g_overkill_ammo_charge_limit;
+
+.vector ok_deathloc;
+.float ok_spawnsys_timer;
+.float ok_lastwep;
+.float ok_item;
+
+.float ok_notice_time;
+.float ammo_charge[Weapons_MAX];
+.float ok_use_ammocharge = _STAT(OK_AMMO_CHARGE);
+.float ok_ammo_charge = _STAT(OK_AMMO_CHARGEPOOL);
+
+.float ok_pauseregen_finished;
+
+void(entity ent, float wep) ok_DecreaseCharge;
+
+void ok_Initialize();
+
+REGISTER_MUTATOR(ok, cvar("g_overkill") && !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
+{
+       MUTATOR_ONADD
+       {
+               ok_Initialize();
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               WEP_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+               WEP_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ok, W_DecreaseAmmo)
+{
+       entity actor = M_ARGV(0, entity);
+       if (actor.ok_use_ammocharge)
+       {
+               ok_DecreaseCharge(actor, PS(actor).m_weapon.m_id);
+               return true;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ok, W_Reload)
+{
+       entity actor = M_ARGV(0, entity);
+       return actor.ok_use_ammocharge;
+}
+
+void W_Blaster_Attack(entity, .entity, float, float, float, float, float, float, float, float, float, float);
+spawnfunc(weapon_hmg);
+spawnfunc(weapon_rpc);
+
+void ok_DecreaseCharge(entity ent, int wep)
+{
+       if(!ent.ok_use_ammocharge) return;
+
+       entity wepent = Weapons_from(wep);
+
+       if (wepent == WEP_Null) return;  // dummy
+
+       ent.ammo_charge[wep] -= max(0, cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
+}
+
+void ok_IncreaseCharge(entity ent, int wep)
+{
+       entity wepent = Weapons_from(wep);
+
+       if (wepent == WEP_Null) return;  // dummy
+
+       if(ent.ok_use_ammocharge)
+       if(!PHYS_INPUT_BUTTON_ATCK(ent)) // not while attacking?
+               ent.ammo_charge[wep] = min(autocvar_g_overkill_ammo_charge_limit, ent.ammo_charge[wep] + cvar(sprintf("g_overkill_ammo_charge_rate_%s", wepent.netname)) * frametime / W_TICSPERFRAME);
+}
+
+float ok_CheckWeaponCharge(entity ent, int wep)
+{
+       if(!ent.ok_use_ammocharge) return true;
+
+       entity wepent = Weapons_from(wep);
+
+       if(wepent == WEP_Null) return false;  // dummy
+
+       return (ent.ammo_charge[wep] >= cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerDamage_Calculate, CBC_ORDER_LAST)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       float frag_deathtype = M_ARGV(3, float);
+
+       if(IS_PLAYER(frag_attacker) && IS_PLAYER(frag_target))
+       if(DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
+       {
+               if(frag_attacker != frag_target)
+               if(frag_target.health > 0)
+               if(STAT(FROZEN, frag_target) == 0)
+               if(!IS_DEAD(frag_target))
+               {
+                       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE);
+                       M_ARGV(6, vector) = '0 0 0';
+               }
+
+               M_ARGV(4, float) = 0;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerDamage_SplitHealthArmor)
+{
+       entity frag_target = M_ARGV(2, entity);
+       float damage_take = M_ARGV(4, float);
+
+       if(damage_take)
+               frag_target.ok_pauseregen_finished = max(frag_target.ok_pauseregen_finished, time + 2);
+}
+
+void ok_DropItem(entity this, entity targ)
+{
+       entity e = new(droppedweapon); // hax
+       e.ok_item = true;
+       e.noalign = true;
+       e.pickup_anyway = true;
+       e.spawnfunc_checked = true;
+       spawnfunc_item_armor_small(e);
+       if (!wasfreed(e)) { // might have been blocked by a mutator
+        set_movetype(e, MOVETYPE_TOSS);
+        e.gravity = 1;
+        e.reset = SUB_Remove;
+        setorigin(e, this.origin + '0 0 32');
+        e.velocity = '0 0 200' + normalize(targ.origin - this.origin) * 500;
+        SUB_SetFade(e, time + 5, 1);
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerDies)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+
+       entity targ = ((frag_attacker) ? frag_attacker : frag_target);
+
+       ok_DropItem(frag_target, targ);
+
+       frag_target.ok_lastwep = PS(frag_target).m_switchweapon.m_id;
+}
+
+MUTATOR_HOOKFUNCTION(ok, MonsterDropItem)
+{
+       entity mon = M_ARGV(0, entity);
+       entity olditem = M_ARGV(1, entity);
+       entity frag_attacker = M_ARGV(2, entity);
+
+       delete(olditem);
+
+       M_ARGV(1, entity) = NULL;
+
+       ok_DropItem(mon, frag_attacker);
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerRegen)
+{
+       entity player = M_ARGV(0, entity);
+
+       // overkill's values are different, so use custom regen
+       if(!STAT(FROZEN, player))
+       {
+               player.armorvalue = CalcRotRegen(player.armorvalue, autocvar_g_balance_armor_regenstable, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear,
+                       1 * frametime * (time > player.ok_pauseregen_finished), 0, 0, 1, 1 * frametime * (time > player.pauserotarmor_finished), autocvar_g_balance_armor_limit);
+               player.health = CalcRotRegen(player.health, autocvar_g_balance_health_regenstable, 0, 100, 1 * frametime * (time > player.ok_pauseregen_finished), 200, 0,
+                       autocvar_g_balance_health_rotlinear, 1 * frametime * (time > player.pauserothealth_finished), autocvar_g_balance_health_limit);
+
+               float minf, maxf, limitf;
+
+               maxf = autocvar_g_balance_fuel_rotstable;
+               minf = autocvar_g_balance_fuel_regenstable;
+               limitf = autocvar_g_balance_fuel_limit;
+
+               player.ammo_fuel = CalcRotRegen(player.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear,
+                       frametime * (time > player.pauseregen_finished) * ((player.items & ITEM_JetpackRegen.m_itemid) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > player.pauserotfuel_finished), limitf);
+       }
+       return true; // return true anyway, as frozen uses no regen
+}
+
+MUTATOR_HOOKFUNCTION(ok, ForbidThrowCurrentWeapon)
+{
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerPreThink)
+{
+       if(intermission_running || gameover)
+               return;
+
+       entity player = M_ARGV(0, entity);
+
+       if(IS_DEAD(player) || !IS_PLAYER(player) || STAT(FROZEN, player))
+               return;
+
+       if(player.ok_lastwep)
+       {
+               Weapon newwep = Weapons_from(player.ok_lastwep);
+               if(player.ok_lastwep == WEP_HMG.m_id)
+                       newwep = WEP_MACHINEGUN;
+               if(player.ok_lastwep == WEP_RPC.m_id)
+                       newwep = WEP_VORTEX;
+               PS(player).m_switchweapon = newwep;
+               player.ok_lastwep = 0;
+       }
+
+       ok_IncreaseCharge(player, PS(player).m_weapon.m_id);
+
+       if(PHYS_INPUT_BUTTON_ATCK2(player))
+       if(!forbidWeaponUse(player) || player.weapon_blocked) // allow if weapon is blocked
+       if(time >= player.jump_interval)
+       {
+               player.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor(player);
+               makevectors(player.v_angle);
+
+               Weapon oldwep = PS(player).m_weapon;
+               PS(player).m_weapon = WEP_BLASTER;
+               W_Blaster_Attack(
+                       player,
+                       weaponentities[0], // TODO: unhardcode
+                       WEP_BLASTER.m_id | HITTYPE_SECONDARY,
+                       WEP_CVAR_SEC(vaporizer, shotangle),
+                       WEP_CVAR_SEC(vaporizer, damage),
+                       WEP_CVAR_SEC(vaporizer, edgedamage),
+                       WEP_CVAR_SEC(vaporizer, radius),
+                       WEP_CVAR_SEC(vaporizer, force),
+                       WEP_CVAR_SEC(vaporizer, speed),
+                       WEP_CVAR_SEC(vaporizer, spread),
+                       WEP_CVAR_SEC(vaporizer, delay),
+                       WEP_CVAR_SEC(vaporizer, lifetime)
+               );
+               PS(player).m_weapon = oldwep;
+       }
+
+       player.weapon_blocked = false;
+
+       player.ok_ammo_charge = player.ammo_charge[PS(player).m_weapon.m_id];
+
+       if(player.ok_use_ammocharge)
+       if(!ok_CheckWeaponCharge(player, PS(player).m_weapon.m_id))
+       {
+               if(autocvar_g_overkill_ammo_charge_notice && time > player.ok_notice_time && PHYS_INPUT_BUTTON_ATCK(player) && IS_REAL_CLIENT(player) && PS(player).m_weapon == PS(player).m_switchweapon)
+               {
+                       //Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_OVERKILL_CHARGE);
+                       player.ok_notice_time = time + 2;
+                       play2(player, SND(DRYFIRE));
+               }
+               Weapon wpn = PS(player).m_weapon;
+               .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+               if(player.(weaponentity).state != WS_CLEAR)
+                       w_ready(wpn, player, weaponentity, PHYS_INPUT_BUTTON_ATCK(player) | (PHYS_INPUT_BUTTON_ATCK2(player) << 1));
+
+               player.weapon_blocked = true;
+       }
+
+       PHYS_INPUT_BUTTON_ATCK2(player) = false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(autocvar_g_overkill_ammo_charge)
+       {
+               FOREACH(Weapons, it != WEP_Null, LAMBDA(player.ammo_charge[it.m_id] = autocvar_g_overkill_ammo_charge_limit));
+
+               player.ok_use_ammocharge = 1;
+               player.ok_notice_time = time;
+       }
+       else
+               player.ok_use_ammocharge = 0;
+
+       // if player changed their weapon while dead, don't switch to their death weapon
+       if(player.impulse)
+               player.ok_lastwep = 0;
+
+       player.ok_pauseregen_finished = time + 2;
+}
+
+void self_spawnfunc_weapon_hmg(entity this) { spawnfunc_weapon_hmg(this); }
+void self_spawnfunc_weapon_rpc(entity this) { spawnfunc_weapon_rpc(this); }
+
+MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
+{
+       entity ent = M_ARGV(0, entity);
+
+       if(autocvar_g_powerups)
+       if(autocvar_g_overkill_powerups_replace)
+       {
+               if(ent.classname == "item_strength")
+               {
+                       entity wep = new(weapon_hmg);
+                       setorigin(wep, ent.origin);
+                       setmodel(wep, MDL_OK_HMG);
+                       wep.ok_item = true;
+                       wep.noalign = ent.noalign;
+                       wep.cnt = ent.cnt;
+                       wep.team = ent.team;
+                       wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
+                       wep.pickup_anyway = true;
+                       wep.spawnfunc_checked = true;
+                       setthink(wep, self_spawnfunc_weapon_hmg);
+                       wep.nextthink = time + 0.1;
+                       return true;
+               }
+
+               if(ent.classname == "item_invincible")
+               {
+                       entity wep = new(weapon_rpc);
+                       setorigin(wep, ent.origin);
+                       setmodel(wep, MDL_OK_RPC);
+                       wep.ok_item = true;
+                       wep.noalign = ent.noalign;
+                       wep.cnt = ent.cnt;
+                       wep.team = ent.team;
+                       wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
+                       wep.pickup_anyway = true;
+                       wep.spawnfunc_checked = true;
+                       setthink(wep, self_spawnfunc_weapon_rpc);
+                       wep.nextthink = time + 0.1;
+                       return true;
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ok, FilterItem)
+{
+       entity item = M_ARGV(0, entity);
+
+       if(item.ok_item)
+               return;
+
+       switch(item.items)
+       {
+               case ITEM_HealthMega.m_itemid: return !(autocvar_g_overkill_100h_anyway);
+               case ITEM_ArmorMega.m_itemid: return !(autocvar_g_overkill_100a_anyway);
+       }
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ok, SpectateCopy)
+{
+       entity spectatee = M_ARGV(0, entity);
+       entity client = M_ARGV(1, entity);
+
+       client.ammo_charge[PS(client).m_weapon.m_id] = spectatee.ammo_charge[PS(spectatee).m_weapon.m_id];
+       client.ok_use_ammocharge = spectatee.ok_use_ammocharge;
+}
+
+MUTATOR_HOOKFUNCTION(ok, SetStartItems)
+{
+       WepSet ok_start_items = (WEPSET(MACHINEGUN) | WEPSET(VORTEX) | WEPSET(SHOTGUN));
+
+       if(WEP_RPC.weaponstart > 0) { ok_start_items |= WEPSET(RPC); }
+       if(WEP_HMG.weaponstart > 0) { ok_start_items |= WEPSET(HMG); }
+
+       start_items |= IT_UNLIMITED_WEAPON_AMMO;
+       start_weapons = warmup_start_weapons = ok_start_items;
+}
+
+MUTATOR_HOOKFUNCTION(ok, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":OK");
+}
+
+MUTATOR_HOOKFUNCTION(ok, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Overkill");
+}
+
+MUTATOR_HOOKFUNCTION(ok, SetModname)
+{
+       M_ARGV(0, string) = "Overkill";
+       return true;
+}
+
+void ok_SetCvars()
+{
+       // hack to force overkill playermodels
+       cvar_settemp("sv_defaultcharacter", "1");
+       cvar_settemp("sv_defaultplayermodel", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
+       cvar_settemp("sv_defaultplayermodel_red", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm");
+       cvar_settemp("sv_defaultplayermodel_blue", "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
+}
+
+void ok_Initialize()
+{
+       ok_SetCvars();
+
+       precache_all_playermodels("models/ok_player/*.dpm");
+
+       WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+       WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+
+       WEP_SHOTGUN.mdl = "ok_shotgun";
+       WEP_MACHINEGUN.mdl = "ok_mg";
+       WEP_VORTEX.mdl = "ok_sniper";
+}
diff --git a/qcsrc/common/mutators/mutator/overkill/sv_overkill.qh b/qcsrc/common/mutators/mutator/overkill/sv_overkill.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 4d4ef59f8ac581b438f48effb461e31b48404e87..e99d4e257a3f7b401868aeda75d8b68c1bdbfa94 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/physical_items/physical_items.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/physical_items/sv_physical_items.qc>
+#endif
index a347cec04e7381d7ea5ba3c558b3b4ae1a6671a9..1aab8b0a84e36f53d672c9b12455a536fffc9d26 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/physical_items/physical_items.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/physical_items/sv_physical_items.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/physical_items/module.inc b/qcsrc/common/mutators/mutator/physical_items/module.inc
deleted file mode 100644 (file)
index 7ed9b03..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "physical_items.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/physical_items/physical_items.qc b/qcsrc/common/mutators/mutator/physical_items/physical_items.qc
deleted file mode 100644 (file)
index f015bae..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-#ifdef IMPLEMENTATION
-int autocvar_g_physical_items;
-float autocvar_g_physical_items_damageforcescale;
-float autocvar_g_physical_items_reset;
-
-REGISTER_MUTATOR(physical_items, cvar("g_physical_items"))
-{
-       // check if we have a physics engine
-       MUTATOR_ONADD
-       {
-               if (!(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")))
-               {
-                       LOG_TRACE("Warning: Physical items are enabled but no physics engine can be used. Reverting to old items.");
-                       return -1;
-               }
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // nothing to roll back
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This cannot be removed at runtime\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-.vector spawn_origin, spawn_angles;
-
-void physical_item_think(entity this)
-{
-       this.nextthink = time;
-
-       this.alpha = this.owner.alpha; // apply fading and ghosting
-
-       if(!this.cnt) // map item, not dropped
-       {
-               // copy ghost item properties
-               this.colormap = this.owner.colormap;
-               this.colormod = this.owner.colormod;
-               this.glowmod = this.owner.glowmod;
-
-               // if the item is not spawned, make sure the invisible / ghost item returns to its origin and stays there
-               if(autocvar_g_physical_items_reset)
-               {
-                       if(this.owner.wait > time) // awaiting respawn
-                       {
-                               setorigin(this, this.spawn_origin);
-                               this.angles = this.spawn_angles;
-                               this.solid = SOLID_NOT;
-                               this.alpha = -1;
-                               set_movetype(this, MOVETYPE_NONE);
-                       }
-                       else
-                       {
-                               this.alpha = 1;
-                               this.solid = SOLID_CORPSE;
-                               set_movetype(this, MOVETYPE_PHYSICS);
-                       }
-               }
-       }
-
-       if(!this.owner.modelindex)
-               delete(this); // the real item is gone, remove this
-}
-
-void physical_item_touch(entity this, entity toucher)
-{
-       if(!this.cnt) // not for dropped items
-       if (ITEM_TOUCH_NEEDKILL())
-       {
-               setorigin(this, this.spawn_origin);
-               this.angles = this.spawn_angles;
-       }
-}
-
-void physical_item_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{
-       if(!this.cnt) // not for dropped items
-       if(ITEM_DAMAGE_NEEDKILL(deathtype))
-       {
-               setorigin(this, this.spawn_origin);
-               this.angles = this.spawn_angles;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(physical_items, Item_Spawn)
-{
-       entity item = M_ARGV(0, entity);
-
-       if(item.owner == NULL && autocvar_g_physical_items <= 1)
-               return;
-       if (item.spawnflags & 1) // floating item
-               return;
-
-       // The actual item can't be physical and trigger at the same time, so make it invisible and use a second entity for physics.
-       // Ugly hack, but unless SOLID_TRIGGER is gotten to work with MOVETYPE_PHYSICS in the engine it can't be fixed.
-       entity wep;
-       wep = spawn();
-       _setmodel(wep, item.model);
-       setsize(wep, item.mins, item.maxs);
-       setorigin(wep, item.origin);
-       wep.angles = item.angles;
-       wep.velocity = item.velocity;
-
-       wep.owner = item;
-       wep.solid = SOLID_CORPSE;
-       set_movetype(wep, MOVETYPE_PHYSICS);
-       wep.takedamage = DAMAGE_AIM;
-       wep.effects |= EF_NOMODELFLAGS; // disable the spinning
-       wep.colormap = item.owner.colormap;
-       wep.glowmod = item.owner.glowmod;
-       wep.damageforcescale = autocvar_g_physical_items_damageforcescale;
-       wep.dphitcontentsmask = item.dphitcontentsmask;
-       wep.cnt = (item.owner != NULL);
-
-       setthink(wep, physical_item_think);
-       wep.nextthink = time;
-       settouch(wep, physical_item_touch);
-       wep.event_damage = physical_item_damage;
-
-       if(!wep.cnt)
-       {
-               // fix the spawn origin
-               setorigin(wep, wep.origin + '0 0 1');
-               droptofloor(wep);
-       }
-
-       wep.spawn_origin = wep.origin;
-       wep.spawn_angles = item.angles;
-
-       item.effects |= EF_NODRAW; // hide the original weapon
-       set_movetype(item, MOVETYPE_FOLLOW);
-       item.aiment = wep; // attach the original weapon
-       setSendEntity(item, func_null);
-}
-#endif
diff --git a/qcsrc/common/mutators/mutator/physical_items/sv_physical_items.qc b/qcsrc/common/mutators/mutator/physical_items/sv_physical_items.qc
new file mode 100644 (file)
index 0000000..62b30e2
--- /dev/null
@@ -0,0 +1,141 @@
+#include "sv_physical_items.qh"
+
+int autocvar_g_physical_items;
+float autocvar_g_physical_items_damageforcescale;
+float autocvar_g_physical_items_reset;
+
+REGISTER_MUTATOR(physical_items, cvar("g_physical_items"))
+{
+       // check if we have a physics engine
+       MUTATOR_ONADD
+       {
+               if (!(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")))
+               {
+                       LOG_TRACE("Warning: Physical items are enabled but no physics engine can be used. Reverting to old items.");
+                       return -1;
+               }
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // nothing to roll back
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This cannot be removed at runtime\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+.vector spawn_origin, spawn_angles;
+
+void physical_item_think(entity this)
+{
+       this.nextthink = time;
+
+       this.alpha = this.owner.alpha; // apply fading and ghosting
+
+       if(!this.cnt) // map item, not dropped
+       {
+               // copy ghost item properties
+               this.colormap = this.owner.colormap;
+               this.colormod = this.owner.colormod;
+               this.glowmod = this.owner.glowmod;
+
+               // if the item is not spawned, make sure the invisible / ghost item returns to its origin and stays there
+               if(autocvar_g_physical_items_reset)
+               {
+                       if(this.owner.wait > time) // awaiting respawn
+                       {
+                               setorigin(this, this.spawn_origin);
+                               this.angles = this.spawn_angles;
+                               this.solid = SOLID_NOT;
+                               this.alpha = -1;
+                               set_movetype(this, MOVETYPE_NONE);
+                       }
+                       else
+                       {
+                               this.alpha = 1;
+                               this.solid = SOLID_CORPSE;
+                               set_movetype(this, MOVETYPE_PHYSICS);
+                       }
+               }
+       }
+
+       if(!this.owner.modelindex)
+               delete(this); // the real item is gone, remove this
+}
+
+void physical_item_touch(entity this, entity toucher)
+{
+       if(!this.cnt) // not for dropped items
+       if (ITEM_TOUCH_NEEDKILL())
+       {
+               setorigin(this, this.spawn_origin);
+               this.angles = this.spawn_angles;
+       }
+}
+
+void physical_item_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{
+       if(!this.cnt) // not for dropped items
+       if(ITEM_DAMAGE_NEEDKILL(deathtype))
+       {
+               setorigin(this, this.spawn_origin);
+               this.angles = this.spawn_angles;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(physical_items, Item_Spawn)
+{
+       entity item = M_ARGV(0, entity);
+
+       if(item.owner == NULL && autocvar_g_physical_items <= 1)
+               return;
+       if (item.spawnflags & 1) // floating item
+               return;
+
+       // The actual item can't be physical and trigger at the same time, so make it invisible and use a second entity for physics.
+       // Ugly hack, but unless SOLID_TRIGGER is gotten to work with MOVETYPE_PHYSICS in the engine it can't be fixed.
+       entity wep;
+       wep = spawn();
+       _setmodel(wep, item.model);
+       setsize(wep, item.mins, item.maxs);
+       setorigin(wep, item.origin);
+       wep.angles = item.angles;
+       wep.velocity = item.velocity;
+
+       wep.owner = item;
+       wep.solid = SOLID_CORPSE;
+       set_movetype(wep, MOVETYPE_PHYSICS);
+       wep.takedamage = DAMAGE_AIM;
+       wep.effects |= EF_NOMODELFLAGS; // disable the spinning
+       wep.colormap = item.owner.colormap;
+       wep.glowmod = item.owner.glowmod;
+       wep.damageforcescale = autocvar_g_physical_items_damageforcescale;
+       wep.dphitcontentsmask = item.dphitcontentsmask;
+       wep.cnt = (item.owner != NULL);
+
+       setthink(wep, physical_item_think);
+       wep.nextthink = time;
+       settouch(wep, physical_item_touch);
+       wep.event_damage = physical_item_damage;
+
+       if(!wep.cnt)
+       {
+               // fix the spawn origin
+               setorigin(wep, wep.origin + '0 0 1');
+               droptofloor(wep);
+       }
+
+       wep.spawn_origin = wep.origin;
+       wep.spawn_angles = item.angles;
+
+       item.effects |= EF_NODRAW; // hide the original weapon
+       set_movetype(item, MOVETYPE_FOLLOW);
+       item.aiment = wep; // attach the original weapon
+       setSendEntity(item, func_null);
+}
diff --git a/qcsrc/common/mutators/mutator/physical_items/sv_physical_items.qh b/qcsrc/common/mutators/mutator/physical_items/sv_physical_items.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index a0bd94d00eab025aa6f843161be5fac9528649ff..5859c55107462dcdfdf9ce339ea99684abf40f21 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/pinata/pinata.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/pinata/sv_pinata.qc>
+#endif
index 1602640e096a854dd01b4687244005e947592550..fdb51ed25ba3f9346487eaafbf8cef9404657a83 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/pinata/pinata.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/pinata/sv_pinata.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/pinata/module.inc b/qcsrc/common/mutators/mutator/pinata/module.inc
deleted file mode 100644 (file)
index 4e22966..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "pinata.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/pinata/pinata.qc b/qcsrc/common/mutators/mutator/pinata/pinata.qc
deleted file mode 100644 (file)
index acdf171..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(pinata, cvar("g_pinata") && !cvar("g_instagib") && !cvar("g_overkill"));
-
-MUTATOR_HOOKFUNCTION(pinata, PlayerDies)
-{
-       entity frag_target = M_ARGV(2, entity);
-
-       FOREACH(Weapons, it != WEP_Null, LAMBDA(
-               if(frag_target.weapons & WepSet_FromWeapon(it))
-               if(PS(frag_target).m_switchweapon != it)
-               if(W_IsWeaponThrowable(frag_target, it.m_id))
-                       W_ThrowNewWeapon(frag_target, it.m_id, false, CENTER_OR_VIEWOFS(frag_target), randomvec() * 175 + '0 0 325');
-       ));
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(pinata, BuildMutatorsString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":Pinata");
-}
-
-MUTATOR_HOOKFUNCTION(pinata, BuildMutatorsPrettyString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Piñata");
-}
-
-#endif
diff --git a/qcsrc/common/mutators/mutator/pinata/sv_pinata.qc b/qcsrc/common/mutators/mutator/pinata/sv_pinata.qc
new file mode 100644 (file)
index 0000000..bc3887e
--- /dev/null
@@ -0,0 +1,27 @@
+#include "sv_pinata.qh"
+
+REGISTER_MUTATOR(pinata, cvar("g_pinata") && !cvar("g_instagib") && !cvar("g_overkill"));
+
+MUTATOR_HOOKFUNCTION(pinata, PlayerDies)
+{
+       entity frag_target = M_ARGV(2, entity);
+
+       FOREACH(Weapons, it != WEP_Null, LAMBDA(
+               if(frag_target.weapons & WepSet_FromWeapon(it))
+               if(PS(frag_target).m_switchweapon != it)
+               if(W_IsWeaponThrowable(frag_target, it.m_id))
+                       W_ThrowNewWeapon(frag_target, it.m_id, false, CENTER_OR_VIEWOFS(frag_target), randomvec() * 175 + '0 0 325');
+       ));
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(pinata, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":Pinata");
+}
+
+MUTATOR_HOOKFUNCTION(pinata, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Piñata");
+}
diff --git a/qcsrc/common/mutators/mutator/pinata/sv_pinata.qh b/qcsrc/common/mutators/mutator/pinata/sv_pinata.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index feeaec8d6966e8319a0d242ae0cd55420b85c42c..846bd8bf82e222f9d2fc34d1d7c2327224bdbdbc 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/random_gravity/random_gravity.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/random_gravity/sv_random_gravity.qc>
+#endif
index 99a11ed63819ac4594feebff6e40a857f1abd956..2cdf724023280a22955a6d307b03df293cd48fe2 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/random_gravity/random_gravity.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/random_gravity/sv_random_gravity.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/random_gravity/module.inc b/qcsrc/common/mutators/mutator/random_gravity/module.inc
deleted file mode 100644 (file)
index 91baa43..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "random_gravity.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/random_gravity/random_gravity.qc b/qcsrc/common/mutators/mutator/random_gravity/random_gravity.qc
deleted file mode 100644 (file)
index 9706aec..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifdef IMPLEMENTATION
-// Random Gravity
-//
-// Mutator by Mario
-// Inspired by Player 2
-
-float autocvar_g_random_gravity_negative_chance;
-float autocvar_g_random_gravity_min;
-float autocvar_g_random_gravity_max;
-float autocvar_g_random_gravity_positive;
-float autocvar_g_random_gravity_negative;
-float autocvar_g_random_gravity_delay;
-
-REGISTER_MUTATOR(random_gravity, cvar("g_random_gravity"))
-{
-       MUTATOR_ONADD
-       {
-               cvar_settemp("sv_gravity", cvar_string("sv_gravity")); // settemp current gravity so it's restored on match end
-       }
-}
-
-float gravity_delay;
-
-MUTATOR_HOOKFUNCTION(random_gravity, SV_StartFrame)
-{
-       if(gameover || !cvar("g_random_gravity")) return false;
-       if(time < gravity_delay) return false;
-       if(time < game_starttime) return false;
-       if(round_handler_IsActive() && !round_handler_IsRoundStarted()) return false;
-
-    if(random() >= autocvar_g_random_gravity_negative_chance)
-        cvar_set("sv_gravity", ftos(bound(autocvar_g_random_gravity_min, random() - random() * -autocvar_g_random_gravity_negative, autocvar_g_random_gravity_max)));
-    else
-        cvar_set("sv_gravity", ftos(bound(autocvar_g_random_gravity_min, random() * autocvar_g_random_gravity_positive, autocvar_g_random_gravity_max)));
-
-       gravity_delay = time + autocvar_g_random_gravity_delay;
-
-       LOG_TRACE("Gravity is now: ", ftos(autocvar_sv_gravity));
-}
-
-MUTATOR_HOOKFUNCTION(random_gravity, BuildMutatorsString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":RandomGravity");
-}
-
-MUTATOR_HOOKFUNCTION(random_gravity, BuildMutatorsPrettyString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Random gravity");
-}
-#endif
diff --git a/qcsrc/common/mutators/mutator/random_gravity/sv_random_gravity.qc b/qcsrc/common/mutators/mutator/random_gravity/sv_random_gravity.qc
new file mode 100644 (file)
index 0000000..f6f28a7
--- /dev/null
@@ -0,0 +1,50 @@
+#include "sv_random_gravity.qh"
+
+// Random Gravity
+
+// Mutator by Mario
+// Inspired by Player 2
+
+float autocvar_g_random_gravity_negative_chance;
+float autocvar_g_random_gravity_min;
+float autocvar_g_random_gravity_max;
+float autocvar_g_random_gravity_positive;
+float autocvar_g_random_gravity_negative;
+float autocvar_g_random_gravity_delay;
+
+REGISTER_MUTATOR(random_gravity, cvar("g_random_gravity"))
+{
+       MUTATOR_ONADD
+       {
+               cvar_settemp("sv_gravity", cvar_string("sv_gravity")); // settemp current gravity so it's restored on match end
+       }
+}
+
+float gravity_delay;
+
+MUTATOR_HOOKFUNCTION(random_gravity, SV_StartFrame)
+{
+       if(gameover || !cvar("g_random_gravity")) return false;
+       if(time < gravity_delay) return false;
+       if(time < game_starttime) return false;
+       if(round_handler_IsActive() && !round_handler_IsRoundStarted()) return false;
+
+    if(random() >= autocvar_g_random_gravity_negative_chance)
+        cvar_set("sv_gravity", ftos(bound(autocvar_g_random_gravity_min, random() - random() * -autocvar_g_random_gravity_negative, autocvar_g_random_gravity_max)));
+    else
+        cvar_set("sv_gravity", ftos(bound(autocvar_g_random_gravity_min, random() * autocvar_g_random_gravity_positive, autocvar_g_random_gravity_max)));
+
+       gravity_delay = time + autocvar_g_random_gravity_delay;
+
+       LOG_TRACE("Gravity is now: ", ftos(autocvar_sv_gravity));
+}
+
+MUTATOR_HOOKFUNCTION(random_gravity, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":RandomGravity");
+}
+
+MUTATOR_HOOKFUNCTION(random_gravity, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Random gravity");
+}
diff --git a/qcsrc/common/mutators/mutator/random_gravity/sv_random_gravity.qh b/qcsrc/common/mutators/mutator/random_gravity/sv_random_gravity.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 0841ae680b745135b4b8ee8845a06a9dd158724f..537a2b37b020116516e125b11118e5dcbcfce0bd 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/rocketflying/rocketflying.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/rocketflying/sv_rocketflying.qc>
+#endif
index 75ca141bf0d9ed83bf42576bb9fc9d32eedfab53..b24545f8c41a10e2ed4e7918f86688463cf217b7 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/rocketflying/rocketflying.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/rocketflying/sv_rocketflying.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/rocketflying/module.inc b/qcsrc/common/mutators/mutator/rocketflying/module.inc
deleted file mode 100644 (file)
index 7036bc4..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "rocketflying.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/rocketflying/rocketflying.qc b/qcsrc/common/mutators/mutator/rocketflying/rocketflying.qc
deleted file mode 100644 (file)
index da7e1c3..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(rocketflying, cvar("g_rocket_flying"));
-
-MUTATOR_HOOKFUNCTION(rocketflying, EditProjectile)
-{
-       entity proj = M_ARGV(1, entity);
-
-       if(proj.classname == "rocket" || proj.classname == "mine")
-       {
-               // kill detonate delay of rockets
-               proj.spawnshieldtime = time;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(rocketflying, BuildMutatorsString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":RocketFlying");
-}
-
-MUTATOR_HOOKFUNCTION(rocketflying, BuildMutatorsPrettyString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Rocket Flying");
-}
-#endif
diff --git a/qcsrc/common/mutators/mutator/rocketflying/sv_rocketflying.qc b/qcsrc/common/mutators/mutator/rocketflying/sv_rocketflying.qc
new file mode 100644 (file)
index 0000000..9f0d8fb
--- /dev/null
@@ -0,0 +1,24 @@
+#include "sv_rocketflying.qh"
+
+REGISTER_MUTATOR(rocketflying, cvar("g_rocket_flying"));
+
+MUTATOR_HOOKFUNCTION(rocketflying, EditProjectile)
+{
+       entity proj = M_ARGV(1, entity);
+
+       if(proj.classname == "rocket" || proj.classname == "mine")
+       {
+               // kill detonate delay of rockets
+               proj.spawnshieldtime = time;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(rocketflying, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":RocketFlying");
+}
+
+MUTATOR_HOOKFUNCTION(rocketflying, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Rocket Flying");
+}
diff --git a/qcsrc/common/mutators/mutator/rocketflying/sv_rocketflying.qh b/qcsrc/common/mutators/mutator/rocketflying/sv_rocketflying.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index bc579ec512d070e8171e16d2a161c007ce9c6d54..bb75554badaf418395aa5f74c09cfbb18a920364 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/rocketminsta/rocketminsta.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/rocketminsta/sv_rocketminsta.qc>
+#endif
index 29a367d3cf869ddb8c70c64c41a2139d2653682c..832c5da2cb6ccd1ab29155df5c647973ffe66527 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/rocketminsta/rocketminsta.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/rocketminsta/sv_rocketminsta.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/rocketminsta/module.inc b/qcsrc/common/mutators/mutator/rocketminsta/module.inc
deleted file mode 100644 (file)
index b7d02a9..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "rocketminsta.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/rocketminsta/rocketminsta.qc b/qcsrc/common/mutators/mutator/rocketminsta/rocketminsta.qc
deleted file mode 100644 (file)
index b0a7403..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifdef IMPLEMENTATION
-#include <common/deathtypes/all.qh>
-#include <server/round_handler.qh>
-
-REGISTER_MUTATOR(rm, cvar("g_instagib"));
-
-MUTATOR_HOOKFUNCTION(rm, PlayerDamage_Calculate)
-{
-       // we do it this way, so rm can be toggled during the match
-       if(!autocvar_g_rm) { return; }
-
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-       float frag_deathtype = M_ARGV(3, float);
-       float frag_damage = M_ARGV(4, float);
-
-       if(DEATH_ISWEAPON(frag_deathtype, WEP_DEVASTATOR))
-       if(frag_attacker == frag_target || frag_target.classname == "nade")
-               frag_damage = 0;
-
-       if(autocvar_g_rm_laser)
-       if(DEATH_ISWEAPON(frag_deathtype, WEP_ELECTRO))
-       if(frag_attacker == frag_target || (round_handler_IsActive() && !round_handler_IsRoundStarted()))
-               frag_damage = 0;
-
-       M_ARGV(4, float) = frag_damage;
-}
-
-MUTATOR_HOOKFUNCTION(rm, PlayerDies)
-{
-       // we do it this way, so rm can be toggled during the match
-       if(!autocvar_g_rm) { return; }
-
-       float frag_deathtype = M_ARGV(3, float);
-
-       if(DEATH_ISWEAPON(frag_deathtype, WEP_DEVASTATOR) || DEATH_ISWEAPON(frag_deathtype, WEP_ELECTRO))
-               M_ARGV(4, float) = 1000; // always gib if it was a vaporizer death
-}
-
-#endif
diff --git a/qcsrc/common/mutators/mutator/rocketminsta/sv_rocketminsta.qc b/qcsrc/common/mutators/mutator/rocketminsta/sv_rocketminsta.qc
new file mode 100644 (file)
index 0000000..04d8099
--- /dev/null
@@ -0,0 +1,39 @@
+#include "sv_rocketminsta.qh"
+
+#include <common/deathtypes/all.qh>
+#include <server/round_handler.qh>
+
+REGISTER_MUTATOR(rm, cvar("g_instagib"));
+
+MUTATOR_HOOKFUNCTION(rm, PlayerDamage_Calculate)
+{
+       // we do it this way, so rm can be toggled during the match
+       if(!autocvar_g_rm) { return; }
+
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       float frag_deathtype = M_ARGV(3, float);
+       float frag_damage = M_ARGV(4, float);
+
+       if(DEATH_ISWEAPON(frag_deathtype, WEP_DEVASTATOR))
+       if(frag_attacker == frag_target || frag_target.classname == "nade")
+               frag_damage = 0;
+
+       if(autocvar_g_rm_laser)
+       if(DEATH_ISWEAPON(frag_deathtype, WEP_ELECTRO))
+       if(frag_attacker == frag_target || (round_handler_IsActive() && !round_handler_IsRoundStarted()))
+               frag_damage = 0;
+
+       M_ARGV(4, float) = frag_damage;
+}
+
+MUTATOR_HOOKFUNCTION(rm, PlayerDies)
+{
+       // we do it this way, so rm can be toggled during the match
+       if(!autocvar_g_rm) { return; }
+
+       float frag_deathtype = M_ARGV(3, float);
+
+       if(DEATH_ISWEAPON(frag_deathtype, WEP_DEVASTATOR) || DEATH_ISWEAPON(frag_deathtype, WEP_ELECTRO))
+               M_ARGV(4, float) = 1000; // always gib if it was a vaporizer death
+}
diff --git a/qcsrc/common/mutators/mutator/rocketminsta/sv_rocketminsta.qh b/qcsrc/common/mutators/mutator/rocketminsta/sv_rocketminsta.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index f88b36a534e3bd57ffde4f4df0f841ceec1e747f..d1db34cf759dba2ecb3cf072f8d89a2fa9308fc8 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/running_guns/running_guns.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/running_guns/sv_running_guns.qc>
+#endif
index 559be4c987bc745bc9467da3a0c50b8a0cd47381..cc0c58eff406110fa57b4eed192ce85470212cd2 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/running_guns/running_guns.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/running_guns/sv_running_guns.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/running_guns/module.inc b/qcsrc/common/mutators/mutator/running_guns/module.inc
deleted file mode 100644 (file)
index 036b70f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "running_guns.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/running_guns/running_guns.qc b/qcsrc/common/mutators/mutator/running_guns/running_guns.qc
deleted file mode 100644 (file)
index cad4d5f..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifdef IMPLEMENTATION
-
-bool autocvar_g_running_guns;
-
-REGISTER_MUTATOR(running_guns, autocvar_g_running_guns);
-
-MUTATOR_HOOKFUNCTION(running_guns, SetDefaultAlpha)
-{
-       default_player_alpha = -1;
-       default_weapon_alpha = +1;
-       return true;
-}
-
-#endif
diff --git a/qcsrc/common/mutators/mutator/running_guns/sv_running_guns.qc b/qcsrc/common/mutators/mutator/running_guns/sv_running_guns.qc
new file mode 100644 (file)
index 0000000..797108e
--- /dev/null
@@ -0,0 +1,11 @@
+#include "sv_running_guns.qh"
+
+bool autocvar_g_running_guns;
+REGISTER_MUTATOR(running_guns, autocvar_g_running_guns);
+
+MUTATOR_HOOKFUNCTION(running_guns, SetDefaultAlpha)
+{
+       default_player_alpha = -1;
+       default_weapon_alpha = +1;
+       return true;
+}
diff --git a/qcsrc/common/mutators/mutator/running_guns/sv_running_guns.qh b/qcsrc/common/mutators/mutator/running_guns/sv_running_guns.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 8e54c1f95e62e2690766d611e71dedccb9c8827c..569c25319b9ed268fbb16ab7aede4fd45624134d 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/sandbox/sandbox.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/sandbox/sv_sandbox.qc>
+#endif
index 81e250c7fa149ad4b10e35cd51eff3243d369bab..86b112934dd8bdc58d00e1bdbd11d7b93a452d3e 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/sandbox/sandbox.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/sandbox/sv_sandbox.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/sandbox/module.inc b/qcsrc/common/mutators/mutator/sandbox/module.inc
deleted file mode 100644 (file)
index 0715d5b..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifdef SVQC
-#include "sandbox.qc"
-
-#endif
diff --git a/qcsrc/common/mutators/mutator/sandbox/sandbox.qc b/qcsrc/common/mutators/mutator/sandbox/sandbox.qc
deleted file mode 100644 (file)
index 577e29c..0000000
+++ /dev/null
@@ -1,825 +0,0 @@
-#ifdef IMPLEMENTATION
-int autocvar_g_sandbox_info;
-bool autocvar_g_sandbox_readonly;
-string autocvar_g_sandbox_storage_name;
-float autocvar_g_sandbox_storage_autosave;
-bool autocvar_g_sandbox_storage_autoload;
-float autocvar_g_sandbox_editor_flood;
-int autocvar_g_sandbox_editor_maxobjects;
-int autocvar_g_sandbox_editor_free;
-float autocvar_g_sandbox_editor_distance_spawn;
-float autocvar_g_sandbox_editor_distance_edit;
-float autocvar_g_sandbox_object_scale_min;
-float autocvar_g_sandbox_object_scale_max;
-float autocvar_g_sandbox_object_material_velocity_min;
-float autocvar_g_sandbox_object_material_velocity_factor;
-
-float autosave_time;
-void sandbox_Database_Load();
-
-REGISTER_MUTATOR(sandbox, cvar("g_sandbox"))
-{
-       MUTATOR_ONADD
-       {
-               autosave_time = time + autocvar_g_sandbox_storage_autosave; // don't save the first server frame
-               if(autocvar_g_sandbox_storage_autoload)
-                       sandbox_Database_Load();
-       }
-}
-
-const float MAX_STORAGE_ATTACHMENTS = 16;
-float object_count;
-.float object_flood;
-.entity object_attach;
-.string material;
-
-.float touch_timer;
-void sandbox_ObjectFunction_Touch(entity this, entity toucher)
-{
-       // apply material impact effects
-
-       if(!this.material)
-               return;
-       if(this.touch_timer > time)
-               return; // don't execute each frame
-       this.touch_timer = time + 0.1;
-
-       // make particle count and sound volume depend on impact speed
-       float intensity;
-       intensity = vlen(this.velocity) + vlen(toucher.velocity);
-       if(intensity) // avoid divisions by 0
-               intensity /= 2; // average the two velocities
-       if (!(intensity >= autocvar_g_sandbox_object_material_velocity_min))
-               return; // impact not strong enough to do anything
-       // now offset intensity and apply it to the effects
-       intensity -= autocvar_g_sandbox_object_material_velocity_min; // start from minimum velocity, not actual velocity
-       intensity = bound(0, intensity * autocvar_g_sandbox_object_material_velocity_factor, 1);
-
-       _sound(this, CH_TRIGGER, strcat("object/impact_", this.material, "_", ftos(ceil(random() * 5)) , ".wav"), VOL_BASE * intensity, ATTEN_NORM);
-       Send_Effect_(strcat("impact_", this.material), this.origin, '0 0 0', ceil(intensity * 10)); // allow a count from 1 to 10
-}
-
-void sandbox_ObjectFunction_Think(entity this)
-{
-       // decide if and how this object can be grabbed
-       if(autocvar_g_sandbox_readonly)
-               this.grab = 0; // no grabbing
-       else if(autocvar_g_sandbox_editor_free < 2 && this.crypto_idfp)
-               this.grab = 1; // owner only
-       else
-               this.grab = 3; // anyone
-
-       // Object owner is stored via player UID, but we also need the owner as an entity (if the player is available on the server).
-       // Therefore, scan for all players, and update the owner as long as the player is present. We must always do this,
-       // since if the owning player disconnects, the object's owner should also be reset.
-
-       // bots can't have objects
-       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), LAMBDA(
-               if(this.crypto_idfp == it.crypto_idfp)
-               {
-                       this.realowner = it;
-                       break;
-               }
-               this.realowner = NULL;
-       ));
-
-       this.nextthink = time;
-
-       CSQCMODEL_AUTOUPDATE(this);
-}
-
-.float old_solid, old_movetype;
-entity sandbox_ObjectEdit_Get(entity this, float permissions)
-{
-       // Returns the traced entity if the player can edit it, and NULL if not.
-       // If permissions if false, the object is returned regardless of editing rights.
-       // Attached objects are SOLID_NOT and do not get traced.
-
-       crosshair_trace_plusvisibletriggers(this);
-       if(vdist(this.origin - trace_ent.origin, >, autocvar_g_sandbox_editor_distance_edit))
-               return NULL; // out of trace range
-       if(trace_ent.classname != "object")
-               return NULL; // entity is not an object
-       if(!permissions)
-               return trace_ent; // don't check permissions, anyone can edit this object
-       if(trace_ent.crypto_idfp == "")
-               return trace_ent; // the player who spawned this object did not have an UID, so anyone can edit it
-       if (!(trace_ent.realowner != this && autocvar_g_sandbox_editor_free < 2))
-               return trace_ent; // object does not belong to the player, and players can only edit their own objects on this server
-       return NULL;
-}
-
-void sandbox_ObjectEdit_Scale(entity e, float f)
-{
-       e.scale = f;
-       if(e.scale)
-       {
-               e.scale = bound(autocvar_g_sandbox_object_scale_min, e.scale, autocvar_g_sandbox_object_scale_max);
-               _setmodel(e, e.model); // reset mins and maxs based on mesh
-               setsize(e, e.mins * e.scale, e.maxs * e.scale); // adapt bounding box size to model size
-       }
-}
-
-void sandbox_ObjectAttach_Remove(entity e);
-void sandbox_ObjectAttach_Set(entity e, entity parent, string s)
-{
-       // attaches e to parent on string s
-
-       // we can't attach to an attachment, for obvious reasons
-       sandbox_ObjectAttach_Remove(e);
-
-       e.old_solid = e.solid; // persist solidity
-       e.old_movetype = e.move_movetype; // persist physics
-       set_movetype(e, MOVETYPE_FOLLOW);
-       e.solid = SOLID_NOT;
-       e.takedamage = DAMAGE_NO;
-
-       setattachment(e, parent, s);
-       e.owner = parent;
-}
-
-void sandbox_ObjectAttach_Remove(entity e)
-{
-       // detaches any object attached to e
-
-       FOREACH_ENTITY_ENT(owner, e,
-       {
-               if(it.classname != "object") continue;
-
-               vector org;
-               org = gettaginfo(it, 0);
-               setattachment(it, NULL, "");
-               it.owner = NULL;
-
-               // objects change origin and angles when detached, so apply previous position
-               setorigin(it, org);
-               it.angles = e.angles; // don't allow detached objects to spin or roll
-
-               it.solid = it.old_solid; // restore persisted solidity
-               set_movetype(it, it.old_movetype); // restore persisted physics
-               it.takedamage = DAMAGE_AIM;
-       });
-}
-
-entity sandbox_ObjectSpawn(entity this, float database)
-{
-       // spawn a new object with default properties
-
-       entity e = new(object);
-       e.takedamage = DAMAGE_AIM;
-       e.damageforcescale = 1;
-       e.solid = SOLID_BBOX; // SOLID_BSP would be best, but can lag the server badly
-       set_movetype(e, MOVETYPE_TOSS);
-       e.frame = 0;
-       e.skin = 0;
-       e.material = string_null;
-       settouch(e, sandbox_ObjectFunction_Touch);
-       setthink(e, sandbox_ObjectFunction_Think);
-       e.nextthink = time;
-       //e.effects |= EF_SELECTABLE; // don't do this all the time, maybe just when editing objects?
-
-       if(!database)
-       {
-               // set the object's owner via player UID
-               // if the player does not have an UID, the owner cannot be stored and his objects may be edited by anyone
-               if(this.crypto_idfp != "")
-                       e.crypto_idfp = strzone(this.crypto_idfp);
-               else
-                       print_to(this, "^1SANDBOX - WARNING: ^7You spawned an object, but lack a player UID. ^1Your objects are not secured and can be edited by any player!");
-
-               // set public object information
-               e.netname = strzone(this.netname); // name of the owner
-               e.message = strzone(strftime(true, "%d-%m-%Y %H:%M:%S")); // creation time
-               e.message2 = strzone(strftime(true, "%d-%m-%Y %H:%M:%S")); // last editing time
-
-               // set origin and direction based on player position and view angle
-               makevectors(this.v_angle);
-               WarpZone_TraceLine(this.origin + this.view_ofs, this.origin + this.view_ofs + v_forward * autocvar_g_sandbox_editor_distance_spawn, MOVE_NORMAL, this);
-               setorigin(e, trace_endpos);
-               e.angles_y = this.v_angle.y;
-       }
-
-       CSQCMODEL_AUTOINIT(e);
-
-       object_count += 1;
-       return e;
-}
-
-void sandbox_ObjectRemove(entity e)
-{
-       sandbox_ObjectAttach_Remove(e); // detach child objects
-
-       // if the object being removed has been selected for attachment by a player, unset it
-       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it.object_attach == e, LAMBDA(it.object_attach = NULL));
-
-       if(e.material)  {       strunzone(e.material);  e.material = string_null;       }
-       if(e.crypto_idfp)       {       strunzone(e.crypto_idfp);       e.crypto_idfp = string_null;    }
-       if(e.netname)   {       strunzone(e.netname);   e.netname = string_null;        }
-       if(e.message)   {       strunzone(e.message);   e.message = string_null;        }
-       if(e.message2)  {       strunzone(e.message2);  e.message2 = string_null;       }
-       delete(e);
-       e = NULL;
-
-       object_count -= 1;
-}
-
-string port_string[MAX_STORAGE_ATTACHMENTS]; // fteqcc crashes if this isn't defined as a global
-
-string sandbox_ObjectPort_Save(entity e, float database)
-{
-       // save object properties, and return them as a string
-       float i = 0;
-       string s;
-       entity head;
-
-       for(head = NULL; (head = find(head, classname, "object")); )
-       {
-               // the main object needs to be first in the array [0] with attached objects following
-               float slot, physics, solidity;
-               if(head == e) // this is the main object, place it first
-               {
-                       slot = 0;
-                       solidity = head.solid; // applied solidity is normal solidity for children
-                       physics = head.move_movetype; // applied physics are normal physics for parents
-               }
-               else if(head.owner == e) // child object, list them in order
-               {
-                       i += 1; // children start from 1
-                       slot = i;
-                       solidity = head.old_solid; // persisted solidity is normal solidity for children
-                       physics = head.old_movetype; // persisted physics are normal physics for children
-                       gettaginfo(head.owner, head.tag_index); // get the name of the tag our object is attached to, used further below
-               }
-               else
-                       continue;
-
-               // ---------------- OBJECT PROPERTY STORAGE: SAVE ----------------
-               if(slot)
-               {
-                       // properties stored only for child objects
-                       if(gettaginfo_name)     port_string[slot] = strcat(port_string[slot], "\"", gettaginfo_name, "\" ");    else    port_string[slot] = strcat(port_string[slot], "\"\" "); // none
-               }
-               else
-               {
-                       // properties stored only for parent objects
-                       if(database)
-                       {
-                               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.origin), " ");
-                               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.angles), " ");
-                       }
-               }
-               // properties stored for all objects
-               port_string[slot] = strcat(port_string[slot], "\"", head.model, "\" ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.skin), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.alpha), " ");
-               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.colormod), " ");
-               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.glowmod), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.frame), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.scale), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(solidity), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(physics), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.damageforcescale), " ");
-               if(head.material)       port_string[slot] = strcat(port_string[slot], "\"", head.material, "\" ");      else    port_string[slot] = strcat(port_string[slot], "\"\" "); // none
-               if(database)
-               {
-                       // properties stored only for the database
-                       if(head.crypto_idfp)    port_string[slot] = strcat(port_string[slot], "\"", head.crypto_idfp, "\" ");   else    port_string[slot] = strcat(port_string[slot], "\"\" "); // none
-                       port_string[slot] = strcat(port_string[slot], "\"", e.netname, "\" ");
-                       port_string[slot] = strcat(port_string[slot], "\"", e.message, "\" ");
-                       port_string[slot] = strcat(port_string[slot], "\"", e.message2, "\" ");
-               }
-       }
-
-       // now apply the array to a simple string, with the ; symbol separating objects
-       s = "";
-       for(i = 0; i <= MAX_STORAGE_ATTACHMENTS; ++i)
-       {
-               if(port_string[i])
-                       s = strcat(s, port_string[i], "; ");
-               port_string[i] = string_null; // fully clear the string
-       }
-
-       return s;
-}
-
-entity sandbox_ObjectPort_Load(entity this, string s, float database)
-{
-       // load object properties, and spawn a new object with them
-       float n, i;
-       entity e = NULL, parent = NULL;
-
-       // separate objects between the ; symbols
-       n = tokenizebyseparator(s, "; ");
-       for(i = 0; i < n; ++i)
-               port_string[i] = argv(i);
-
-       // now separate and apply the properties of each object
-       for(i = 0; i < n; ++i)
-       {
-               float argv_num;
-               string tagname = string_null;
-               argv_num = 0;
-               tokenize_console(port_string[i]);
-               e = sandbox_ObjectSpawn(this, database);
-
-               // ---------------- OBJECT PROPERTY STORAGE: LOAD ----------------
-               if(i)
-               {
-                       // properties stored only for child objects
-                       if(argv(argv_num) != "")        tagname = argv(argv_num);       else tagname = string_null;     ++argv_num;
-               }
-               else
-               {
-                       // properties stored only for parent objects
-                       if(database)
-                       {
-                               setorigin(e, stov(argv(argv_num)));     ++argv_num;
-                               e.angles = stov(argv(argv_num));        ++argv_num;
-                       }
-                       parent = e; // mark parent objects as such
-               }
-               // properties stored for all objects
-               _setmodel(e, argv(argv_num));   ++argv_num;
-               e.skin = stof(argv(argv_num));  ++argv_num;
-               e.alpha = stof(argv(argv_num)); ++argv_num;
-               e.colormod = stov(argv(argv_num));      ++argv_num;
-               e.glowmod = stov(argv(argv_num));       ++argv_num;
-               e.frame = stof(argv(argv_num)); ++argv_num;
-               sandbox_ObjectEdit_Scale(e, stof(argv(argv_num)));      ++argv_num;
-               e.solid = e.old_solid = stof(argv(argv_num));   ++argv_num;
-               e.old_movetype = stof(argv(argv_num));  ++argv_num;
-               set_movetype(e, e.old_movetype);
-               e.damageforcescale = stof(argv(argv_num));      ++argv_num;
-               if(e.material)  strunzone(e.material);  if(argv(argv_num) != "")        e.material = strzone(argv(argv_num));   else    e.material = string_null;       ++argv_num;
-               if(database)
-               {
-                       // properties stored only for the database
-                       if(e.crypto_idfp)       strunzone(e.crypto_idfp);       if(argv(argv_num) != "")        e.crypto_idfp = strzone(argv(argv_num));        else    e.crypto_idfp = string_null;    ++argv_num;
-                       if(e.netname)   strunzone(e.netname);   e.netname = strzone(argv(argv_num));    ++argv_num;
-                       if(e.message)   strunzone(e.message);   e.message = strzone(argv(argv_num));    ++argv_num;
-                       if(e.message2)  strunzone(e.message2);  e.message2 = strzone(argv(argv_num));   ++argv_num;
-               }
-
-               // attach last
-               if(i)
-                       sandbox_ObjectAttach_Set(e, parent, tagname);
-       }
-
-       for(i = 0; i <= MAX_STORAGE_ATTACHMENTS; ++i)
-               port_string[i] = string_null; // fully clear the string
-
-       return e;
-}
-
-void sandbox_Database_Save()
-{
-       // saves all objects to the database file
-       entity head;
-       string file_name;
-       float file_get;
-
-       file_name = strcat("sandbox/storage_", autocvar_g_sandbox_storage_name, "_", GetMapname(), ".txt");
-       file_get = fopen(file_name, FILE_WRITE);
-       fputs(file_get, strcat("// sandbox storage \"", autocvar_g_sandbox_storage_name, "\" for map \"", GetMapname(), "\" last updated ", strftime(true, "%d-%m-%Y %H:%M:%S")));
-       fputs(file_get, strcat(" containing ", ftos(object_count), " objects\n"));
-
-       for(head = NULL; (head = find(head, classname, "object")); )
-       {
-               // attached objects are persisted separately, ignore them here
-               if(head.owner != NULL)
-                       continue;
-
-               // use a line of text for each object, listing all properties
-               fputs(file_get, strcat(sandbox_ObjectPort_Save(head, true), "\n"));
-       }
-       fclose(file_get);
-}
-
-void sandbox_Database_Load()
-{
-       // loads all objects from the database file
-       string file_read, file_name;
-       float file_get, i;
-
-       file_name = strcat("sandbox/storage_", autocvar_g_sandbox_storage_name, "_", GetMapname(), ".txt");
-       file_get = fopen(file_name, FILE_READ);
-       if(file_get < 0)
-       {
-               if(autocvar_g_sandbox_info > 0)
-                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7could not find storage file ^3", file_name, "^7, no objects were loaded\n"));
-       }
-       else
-       {
-               for (;;)
-               {
-                       file_read = fgets(file_get);
-                       if(file_read == "")
-                               break;
-                       if(substring(file_read, 0, 2) == "//")
-                               continue;
-                       if(substring(file_read, 0, 1) == "#")
-                               continue;
-
-                       entity e;
-                       e = sandbox_ObjectPort_Load(NULL, file_read, true);
-
-                       if(e.material)
-                       {
-                               // since objects are being loaded for the first time, precache material sounds for each
-                               for (i = 1; i <= 5; i++) // 5 sounds in total
-                                       precache_sound(strcat("object/impact_", e.material, "_", ftos(i), ".wav"));
-                       }
-               }
-               if(autocvar_g_sandbox_info > 0)
-                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7successfully loaded storage file ^3", file_name, "\n"));
-       }
-       fclose(file_get);
-}
-
-MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
-{
-       if(MUTATOR_RETURNVALUE) // command was already handled?
-               return;
-
-       entity player = M_ARGV(0, entity);
-       string cmd_name = M_ARGV(1, string);
-       int cmd_argc = M_ARGV(2, int);
-
-       if(cmd_name == "g_sandbox")
-       {
-               if(autocvar_g_sandbox_readonly)
-               {
-                       print_to(player, "^2SANDBOX - INFO: ^7Sandbox mode is active, but in read-only mode. Sandbox commands cannot be used");
-                       return true;
-               }
-               if(cmd_argc < 2)
-               {
-                       print_to(player, "^2SANDBOX - INFO: ^7Sandbox mode is active. For usage information, type 'sandbox help'");
-                       return true;
-               }
-
-               switch(argv(1))
-               {
-                       entity e;
-                       int j;
-                       string s;
-
-                       // ---------------- COMMAND: HELP ----------------
-                       case "help":
-                               print_to(player, "You can use the following sandbox commands:");
-                               print_to(player, "^7\"^2object_spawn ^3models/foo/bar.md3^7\" spawns a new object in front of the player, and gives it the specified model");
-                               print_to(player, "^7\"^2object_remove^7\" removes the object the player is looking at. Players can only remove their own objects");
-                               print_to(player, "^7\"^2object_duplicate ^3value^7\" duplicates the object, if the player has copying rights over the original");
-                               print_to(player, "^3copy value ^7- copies the properties of the object to the specified client cvar");
-                               print_to(player, "^3paste value ^7- spawns an object with the given properties. Properties or cvars must be specified as follows; eg1: \"0 1 2 ...\", eg2: \"$cl_cvar\"");
-                               print_to(player, "^7\"^2object_attach ^3property value^7\" attaches one object to another. Players can only attach their own objects");
-                               print_to(player, "^3get ^7- selects the object you are facing as the object to be attached");
-                               print_to(player, "^3set value ^7- attaches the previously selected object to the object you are facing, on the specified bone");
-                               print_to(player, "^3remove ^7- detaches all objects from the object you are facing");
-                               print_to(player, "^7\"^2object_edit ^3property value^7\" edits the given property of the object. Players can only edit their own objects");
-                               print_to(player, "^3skin value ^7- changes the skin of the object");
-                               print_to(player, "^3alpha value ^7- sets object transparency");
-                               print_to(player, "^3colormod \"value_x value_y value_z\" ^7- main object color");
-                               print_to(player, "^3glowmod \"value_x value_y value_z\" ^7- glow object color");
-                               print_to(player, "^3frame value ^7- object animation frame, for self-animated models");
-                               print_to(player, "^3scale value ^7- changes object scale. 0.5 is half size and 2 is double size");
-                               print_to(player, "^3solidity value ^7- object collisions, 0 = non-solid, 1 = solid");
-                               print_to(player, "^3physics value ^7- object physics, 0 = static, 1 = movable, 2 = physical");
-                               print_to(player, "^3force value ^7- amount of force applied to objects that are shot");
-                               print_to(player, "^3material value ^7- sets the material of the object. Default materials are: metal, stone, wood, flesh");
-                               print_to(player, "^7\"^2object_claim^7\" sets the player as the owner of the object, if he has the right to edit it");
-                               print_to(player, "^7\"^2object_info ^3value^7\" shows public information about the object");
-                               print_to(player, "^3object ^7- prints general information about the object, such as owner and creation / editing date");
-                               print_to(player, "^3mesh ^7- prints information about the object's mesh, including skeletal bones");
-                               print_to(player, "^3attachments ^7- prints information about the object's attachments");
-                               print_to(player, "^7The ^1drag object ^7key can be used to grab and carry objects. Players can only grab their own objects");
-                               return true;
-
-                       // ---------------- COMMAND: OBJECT, SPAWN ----------------
-                       case "object_spawn":
-                               if(time < player.object_flood)
-                               {
-                                       print_to(player, strcat("^1SANDBOX - WARNING: ^7Flood protection active. Please wait ^3", ftos(player.object_flood - time), " ^7seconds beofore spawning another object"));
-                                       return true;
-                               }
-                               player.object_flood = time + autocvar_g_sandbox_editor_flood;
-                               if(object_count >= autocvar_g_sandbox_editor_maxobjects)
-                               {
-                                       print_to(player, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
-                                       return true;
-                               }
-                               if(cmd_argc < 3)
-                               {
-                                       print_to(player, "^1SANDBOX - WARNING: ^7Attempted to spawn an object without specifying a model. Please specify the path to your model file after the 'object_spawn' command");
-                                       return true;
-                               }
-                               if (!(fexists(argv(2))))
-                               {
-                                       print_to(player, "^1SANDBOX - WARNING: ^7Attempted to spawn an object with a non-existent model. Make sure the path to your model file is correct");
-                                       return true;
-                               }
-
-                               e = sandbox_ObjectSpawn(player, false);
-                               _setmodel(e, argv(2));
-
-                               if(autocvar_g_sandbox_info > 0)
-                                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " spawned an object at origin ^3", vtos(e.origin), "\n"));
-                               return true;
-
-                       // ---------------- COMMAND: OBJECT, REMOVE ----------------
-                       case "object_remove":
-                               e = sandbox_ObjectEdit_Get(player, true);
-                               if(e != NULL)
-                               {
-                                       if(autocvar_g_sandbox_info > 0)
-                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " removed an object at origin ^3", vtos(e.origin), "\n"));
-                                       sandbox_ObjectRemove(e);
-                                       return true;
-                               }
-
-                               print_to(player, "^1SANDBOX - WARNING: ^7Object could not be removed. Make sure you are facing an object that you have edit rights over");
-                               return true;
-
-                       // ---------------- COMMAND: OBJECT, DUPLICATE ----------------
-                       case "object_duplicate":
-                               switch(argv(2))
-                               {
-                                       case "copy":
-                                               // copies customizable properties of the selected object to the clipboard cvar
-                                               e = sandbox_ObjectEdit_Get(player, autocvar_g_sandbox_editor_free); // can we copy objects we can't edit?
-                                               if(e != NULL)
-                                               {
-                                                       s = sandbox_ObjectPort_Save(e, false);
-                                                       s = strreplace("\"", "\\\"", s);
-                                                       stuffcmd(player, strcat("set ", argv(3), " \"", s, "\""));
-
-                                                       print_to(player, "^2SANDBOX - INFO: ^7Object copied to clipboard");
-                                                       return true;
-                                               }
-                                               print_to(player, "^1SANDBOX - WARNING: ^7Object could not be copied. Make sure you are facing an object that you have copy rights over");
-                                               return true;
-
-                                       case "paste":
-                                               // spawns a new object using the properties in the player's clipboard cvar
-                                               if(time < player.object_flood)
-                                               {
-                                                       print_to(player, strcat("^1SANDBOX - WARNING: ^7Flood protection active. Please wait ^3", ftos(player.object_flood - time), " ^7seconds beofore spawning another object"));
-                                                       return true;
-                                               }
-                                               player.object_flood = time + autocvar_g_sandbox_editor_flood;
-                                               if(argv(3) == "") // no object in clipboard
-                                               {
-                                                       print_to(player, "^1SANDBOX - WARNING: ^7No object in clipboard. You must copy an object before you can paste it");
-                                                       return true;
-                                               }
-                                               if(object_count >= autocvar_g_sandbox_editor_maxobjects)
-                                               {
-                                                       print_to(player, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
-                                                       return true;
-                                               }
-                                               e = sandbox_ObjectPort_Load(player, argv(3), false);
-
-                                               print_to(player, "^2SANDBOX - INFO: ^7Object pasted successfully");
-                                               if(autocvar_g_sandbox_info > 0)
-                                                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " pasted an object at origin ^3", vtos(e.origin), "\n"));
-                                               return true;
-                               }
-                               return true;
-
-                       // ---------------- COMMAND: OBJECT, ATTACH ----------------
-                       case "object_attach":
-                               switch(argv(2))
-                               {
-                                       case "get":
-                                               // select e as the object as meant to be attached
-                                               e = sandbox_ObjectEdit_Get(player, true);
-                                               if(e != NULL)
-                                               {
-                                                       player.object_attach = e;
-                                                       print_to(player, "^2SANDBOX - INFO: ^7Object selected for attachment");
-                                                       return true;
-                                               }
-                                               print_to(player, "^1SANDBOX - WARNING: ^7Object could not be selected for attachment. Make sure you are facing an object that you have edit rights over");
-                                               return true;
-                                       case "set":
-                                               if(player.object_attach == NULL)
-                                               {
-                                                       print_to(player, "^1SANDBOX - WARNING: ^7No object selected for attachment. Please select an object to be attached first.");
-                                                       return true;
-                                               }
-
-                                               // attaches the previously selected object to e
-                                               e = sandbox_ObjectEdit_Get(player, true);
-                                               if(e != NULL)
-                                               {
-                                                       sandbox_ObjectAttach_Set(player.object_attach, e, argv(3));
-                                                       player.object_attach = NULL; // object was attached, no longer keep it scheduled for attachment
-                                                       print_to(player, "^2SANDBOX - INFO: ^7Object attached successfully");
-                                                       if(autocvar_g_sandbox_info > 1)
-                                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " attached objects at origin ^3", vtos(e.origin), "\n"));
-                                                       return true;
-                                               }
-                                               print_to(player, "^1SANDBOX - WARNING: ^7Object could not be attached to the parent. Make sure you are facing an object that you have edit rights over");
-                                               return true;
-                                       case "remove":
-                                               // removes e if it was attached
-                                               e = sandbox_ObjectEdit_Get(player, true);
-                                               if(e != NULL)
-                                               {
-                                                       sandbox_ObjectAttach_Remove(e);
-                                                       print_to(player, "^2SANDBOX - INFO: ^7Child objects detached successfully");
-                                                       if(autocvar_g_sandbox_info > 1)
-                                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " detached objects at origin ^3", vtos(e.origin), "\n"));
-                                                       return true;
-                                               }
-                                               print_to(player, "^1SANDBOX - WARNING: ^7Child objects could not be detached. Make sure you are facing an object that you have edit rights over");
-                                               return true;
-                               }
-                               return true;
-
-                       // ---------------- COMMAND: OBJECT, EDIT ----------------
-                       case "object_edit":
-                               if(argv(2) == "")
-                               {
-                                       print_to(player, "^1SANDBOX - WARNING: ^7Too few parameters. You must specify a property to edit");
-                                       return true;
-                               }
-
-                               e = sandbox_ObjectEdit_Get(player, true);
-                               if(e != NULL)
-                               {
-                                       switch(argv(2))
-                                       {
-                                               case "skin":
-                                                       e.skin = stof(argv(3));
-                                                       break;
-                                               case "alpha":
-                                                       e.alpha = stof(argv(3));
-                                                       break;
-                                               case "color_main":
-                                                       e.colormod = stov(argv(3));
-                                                       break;
-                                               case "color_glow":
-                                                       e.glowmod = stov(argv(3));
-                                                       break;
-                                               case "frame":
-                                                       e.frame = stof(argv(3));
-                                                       break;
-                                               case "scale":
-                                                       sandbox_ObjectEdit_Scale(e, stof(argv(3)));
-                                                       break;
-                                               case "solidity":
-                                                       switch(argv(3))
-                                                       {
-                                                               case "0": // non-solid
-                                                                       e.solid = SOLID_TRIGGER;
-                                                                       break;
-                                                               case "1": // solid
-                                                                       e.solid = SOLID_BBOX;
-                                                                       break;
-                                                               default:
-                                                                       break;
-                                                       }
-                                               case "physics":
-                                                       switch(argv(3))
-                                                       {
-                                                               case "0": // static
-                                                                       set_movetype(e, MOVETYPE_NONE);
-                                                                       break;
-                                                               case "1": // movable
-                                                                       set_movetype(e, MOVETYPE_TOSS);
-                                                                       break;
-                                                               case "2": // physical
-                                                                       set_movetype(e, MOVETYPE_PHYSICS);
-                                                                       break;
-                                                               default:
-                                                                       break;
-                                                       }
-                                                       break;
-                                               case "force":
-                                                       e.damageforcescale = stof(argv(3));
-                                                       break;
-                                               case "material":
-                                                       if(e.material)  strunzone(e.material);
-                                                       if(argv(3))
-                                                       {
-                                                               for (j = 1; j <= 5; j++) // precache material sounds, 5 in total
-                                                                       precache_sound(strcat("object/impact_", argv(3), "_", ftos(j), ".wav"));
-                                                               e.material = strzone(argv(3));
-                                                       }
-                                                       else
-                                                               e.material = string_null; // no material
-                                                       break;
-                                               default:
-                                                       print_to(player, "^1SANDBOX - WARNING: ^7Invalid object property. For usage information, type 'sandbox help'");
-                                                       return true;
-                                       }
-
-                                       // update last editing time
-                                       if(e.message2)  strunzone(e.message2);
-                                       e.message2 = strzone(strftime(true, "%d-%m-%Y %H:%M:%S"));
-
-                                       if(autocvar_g_sandbox_info > 1)
-                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " edited property ^3", argv(2), " ^7of an object at origin ^3", vtos(e.origin), "\n"));
-                                       return true;
-                               }
-
-                               print_to(player, "^1SANDBOX - WARNING: ^7Object could not be edited. Make sure you are facing an object that you have edit rights over");
-                               return true;
-
-                       // ---------------- COMMAND: OBJECT, CLAIM ----------------
-                       case "object_claim":
-                               // if the player can edit an object but is not its owner, this can be used to claim that object
-                               if(player.crypto_idfp == "")
-                               {
-                                       print_to(player, "^1SANDBOX - WARNING: ^7You do not have a player UID, and cannot claim objects");
-                                       return true;
-                               }
-                               e = sandbox_ObjectEdit_Get(player, true);
-                               if(e != NULL)
-                               {
-                                       // update the owner's name
-                                       // Do this before checking if you're already the owner and skipping if such, so we
-                                       // also update the player's nickname if he changed it (but has the same player UID)
-                                       if(e.netname != player.netname)
-                                       {
-                                               if(e.netname)   strunzone(e.netname);
-                                               e.netname = strzone(player.netname);
-                                               print_to(player, "^2SANDBOX - INFO: ^7Object owner name updated");
-                                       }
-
-                                       if(e.crypto_idfp == player.crypto_idfp)
-                                       {
-                                               print_to(player, "^2SANDBOX - INFO: ^7Object is already yours, nothing to claim");
-                                               return true;
-                                       }
-
-                                       if(e.crypto_idfp)       strunzone(e.crypto_idfp);
-                                       e.crypto_idfp = strzone(player.crypto_idfp);
-
-                                       print_to(player, "^2SANDBOX - INFO: ^7Object claimed successfully");
-                               }
-                               print_to(player, "^1SANDBOX - WARNING: ^7Object could not be claimed. Make sure you are facing an object that you have edit rights over");
-                               return true;
-
-                       // ---------------- COMMAND: OBJECT, INFO ----------------
-                       case "object_info":
-                               // prints public information about the object to the player
-                               e = sandbox_ObjectEdit_Get(player, false);
-                               if(e != NULL)
-                               {
-                                       switch(argv(2))
-                                       {
-                                               case "object":
-                                                       print_to(player, strcat("^2SANDBOX - INFO: ^7Object is owned by \"^7", e.netname, "^7\", created \"^3", e.message, "^7\", last edited \"^3", e.message2, "^7\""));
-                                                       return true;
-                                               case "mesh":
-                                                       s = "";
-                                                       FOR_EACH_TAG(e)
-                                                               s = strcat(s, "^7\"^5", gettaginfo_name, "^7\", ");
-                                                       print_to(player, strcat("^2SANDBOX - INFO: ^7Object mesh is \"^3", e.model, "^7\" at animation frame ^3", ftos(e.frame), " ^7containing the following tags: ", s));
-                                                       return true;
-                                               case "attachments":
-                                                       // this should show the same info as 'mesh' but for attachments
-                                                       s = "";
-                                                       j = 0;
-                                                       FOREACH_ENTITY_ENT(owner, e,
-                                                       {
-                                                               if(it.classname != "object") continue;
-
-                                                               ++j; // start from 1
-                                                               gettaginfo(e, it.tag_index);
-                                                               s = strcat(s, "^1attachment ", ftos(j), "^7 has mesh \"^3", it.model, "^7\" at animation frame ^3", ftos(it.frame));
-                                                               s = strcat(s, "^7 and is attached to bone \"^5", gettaginfo_name, "^7\", ");
-                                                       });
-                                                       if(j) // object contains attachments
-                                                               print_to(player, strcat("^2SANDBOX - INFO: ^7Object contains the following ^1", ftos(j), "^7 attachment(s): ", s));
-                                                       else
-                                                               print_to(player, "^2SANDBOX - INFO: ^7Object contains no attachments");
-                                                       return true;
-                                       }
-                               }
-                               print_to(player, "^1SANDBOX - WARNING: ^7No information could be found. Make sure you are facing an object");
-                               return true;
-
-                       // ---------------- COMMAND: DEFAULT ----------------
-                       default:
-                               print_to(player, "Invalid command. For usage information, type 'sandbox help'");
-                               return true;
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(sandbox, SV_StartFrame)
-{
-       if(!autocvar_g_sandbox_storage_autosave)
-               return;
-       if(time < autosave_time)
-               return;
-       autosave_time = time + autocvar_g_sandbox_storage_autosave;
-
-       sandbox_Database_Save();
-
-       return true;
-}
-#endif
diff --git a/qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qc b/qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qc
new file mode 100644 (file)
index 0000000..a2211fe
--- /dev/null
@@ -0,0 +1,823 @@
+#include "sv_sandbox.qh"
+
+int autocvar_g_sandbox_info;
+bool autocvar_g_sandbox_readonly;
+string autocvar_g_sandbox_storage_name;
+float autocvar_g_sandbox_storage_autosave;
+bool autocvar_g_sandbox_storage_autoload;
+float autocvar_g_sandbox_editor_flood;
+int autocvar_g_sandbox_editor_maxobjects;
+int autocvar_g_sandbox_editor_free;
+float autocvar_g_sandbox_editor_distance_spawn;
+float autocvar_g_sandbox_editor_distance_edit;
+float autocvar_g_sandbox_object_scale_min;
+float autocvar_g_sandbox_object_scale_max;
+float autocvar_g_sandbox_object_material_velocity_min;
+float autocvar_g_sandbox_object_material_velocity_factor;
+
+float autosave_time;
+void sandbox_Database_Load();
+
+REGISTER_MUTATOR(sandbox, cvar("g_sandbox"))
+{
+       MUTATOR_ONADD
+       {
+               autosave_time = time + autocvar_g_sandbox_storage_autosave; // don't save the first server frame
+               if(autocvar_g_sandbox_storage_autoload)
+                       sandbox_Database_Load();
+       }
+}
+
+const float MAX_STORAGE_ATTACHMENTS = 16;
+float object_count;
+.float object_flood;
+.entity object_attach;
+.string material;
+
+.float touch_timer;
+void sandbox_ObjectFunction_Touch(entity this, entity toucher)
+{
+       // apply material impact effects
+
+       if(!this.material)
+               return;
+       if(this.touch_timer > time)
+               return; // don't execute each frame
+       this.touch_timer = time + 0.1;
+
+       // make particle count and sound volume depend on impact speed
+       float intensity;
+       intensity = vlen(this.velocity) + vlen(toucher.velocity);
+       if(intensity) // avoid divisions by 0
+               intensity /= 2; // average the two velocities
+       if (!(intensity >= autocvar_g_sandbox_object_material_velocity_min))
+               return; // impact not strong enough to do anything
+       // now offset intensity and apply it to the effects
+       intensity -= autocvar_g_sandbox_object_material_velocity_min; // start from minimum velocity, not actual velocity
+       intensity = bound(0, intensity * autocvar_g_sandbox_object_material_velocity_factor, 1);
+
+       _sound(this, CH_TRIGGER, strcat("object/impact_", this.material, "_", ftos(ceil(random() * 5)) , ".wav"), VOL_BASE * intensity, ATTEN_NORM);
+       Send_Effect_(strcat("impact_", this.material), this.origin, '0 0 0', ceil(intensity * 10)); // allow a count from 1 to 10
+}
+
+void sandbox_ObjectFunction_Think(entity this)
+{
+       // decide if and how this object can be grabbed
+       if(autocvar_g_sandbox_readonly)
+               this.grab = 0; // no grabbing
+       else if(autocvar_g_sandbox_editor_free < 2 && this.crypto_idfp)
+               this.grab = 1; // owner only
+       else
+               this.grab = 3; // anyone
+
+       // Object owner is stored via player UID, but we also need the owner as an entity (if the player is available on the server).
+       // Therefore, scan for all players, and update the owner as long as the player is present. We must always do this,
+       // since if the owning player disconnects, the object's owner should also be reset.
+
+       // bots can't have objects
+       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), LAMBDA(
+               if(this.crypto_idfp == it.crypto_idfp)
+               {
+                       this.realowner = it;
+                       break;
+               }
+               this.realowner = NULL;
+       ));
+
+       this.nextthink = time;
+
+       CSQCMODEL_AUTOUPDATE(this);
+}
+
+.float old_solid, old_movetype;
+entity sandbox_ObjectEdit_Get(entity this, float permissions)
+{
+       // Returns the traced entity if the player can edit it, and NULL if not.
+       // If permissions if false, the object is returned regardless of editing rights.
+       // Attached objects are SOLID_NOT and do not get traced.
+
+       crosshair_trace_plusvisibletriggers(this);
+       if(vdist(this.origin - trace_ent.origin, >, autocvar_g_sandbox_editor_distance_edit))
+               return NULL; // out of trace range
+       if(trace_ent.classname != "object")
+               return NULL; // entity is not an object
+       if(!permissions)
+               return trace_ent; // don't check permissions, anyone can edit this object
+       if(trace_ent.crypto_idfp == "")
+               return trace_ent; // the player who spawned this object did not have an UID, so anyone can edit it
+       if (!(trace_ent.realowner != this && autocvar_g_sandbox_editor_free < 2))
+               return trace_ent; // object does not belong to the player, and players can only edit their own objects on this server
+       return NULL;
+}
+
+void sandbox_ObjectEdit_Scale(entity e, float f)
+{
+       e.scale = f;
+       if(e.scale)
+       {
+               e.scale = bound(autocvar_g_sandbox_object_scale_min, e.scale, autocvar_g_sandbox_object_scale_max);
+               _setmodel(e, e.model); // reset mins and maxs based on mesh
+               setsize(e, e.mins * e.scale, e.maxs * e.scale); // adapt bounding box size to model size
+       }
+}
+
+void sandbox_ObjectAttach_Remove(entity e);
+void sandbox_ObjectAttach_Set(entity e, entity parent, string s)
+{
+       // attaches e to parent on string s
+
+       // we can't attach to an attachment, for obvious reasons
+       sandbox_ObjectAttach_Remove(e);
+
+       e.old_solid = e.solid; // persist solidity
+       e.old_movetype = e.move_movetype; // persist physics
+       set_movetype(e, MOVETYPE_FOLLOW);
+       e.solid = SOLID_NOT;
+       e.takedamage = DAMAGE_NO;
+
+       setattachment(e, parent, s);
+       e.owner = parent;
+}
+
+void sandbox_ObjectAttach_Remove(entity e)
+{
+       // detaches any object attached to e
+
+       IL_EACH(g_sandbox_objects, it.owner == e,
+       {
+               vector org = gettaginfo(it, 0);
+               setattachment(it, NULL, "");
+               it.owner = NULL;
+
+               // objects change origin and angles when detached, so apply previous position
+               setorigin(it, org);
+               it.angles = e.angles; // don't allow detached objects to spin or roll
+
+               it.solid = it.old_solid; // restore persisted solidity
+               set_movetype(it, it.old_movetype); // restore persisted physics
+               it.takedamage = DAMAGE_AIM;
+       });
+}
+
+entity sandbox_ObjectSpawn(entity this, float database)
+{
+       // spawn a new object with default properties
+
+       entity e = new(object);
+       IL_PUSH(g_sandbox_objects, e);
+       e.takedamage = DAMAGE_AIM;
+       e.damageforcescale = 1;
+       e.solid = SOLID_BBOX; // SOLID_BSP would be best, but can lag the server badly
+       set_movetype(e, MOVETYPE_TOSS);
+       e.frame = 0;
+       e.skin = 0;
+       e.material = string_null;
+       settouch(e, sandbox_ObjectFunction_Touch);
+       setthink(e, sandbox_ObjectFunction_Think);
+       e.nextthink = time;
+       //e.effects |= EF_SELECTABLE; // don't do this all the time, maybe just when editing objects?
+
+       if(!database)
+       {
+               // set the object's owner via player UID
+               // if the player does not have an UID, the owner cannot be stored and his objects may be edited by anyone
+               if(this.crypto_idfp != "")
+                       e.crypto_idfp = strzone(this.crypto_idfp);
+               else
+                       print_to(this, "^1SANDBOX - WARNING: ^7You spawned an object, but lack a player UID. ^1Your objects are not secured and can be edited by any player!");
+
+               // set public object information
+               e.netname = strzone(this.netname); // name of the owner
+               e.message = strzone(strftime(true, "%d-%m-%Y %H:%M:%S")); // creation time
+               e.message2 = strzone(strftime(true, "%d-%m-%Y %H:%M:%S")); // last editing time
+
+               // set origin and direction based on player position and view angle
+               makevectors(this.v_angle);
+               WarpZone_TraceLine(this.origin + this.view_ofs, this.origin + this.view_ofs + v_forward * autocvar_g_sandbox_editor_distance_spawn, MOVE_NORMAL, this);
+               setorigin(e, trace_endpos);
+               e.angles_y = this.v_angle.y;
+       }
+
+       CSQCMODEL_AUTOINIT(e);
+
+       object_count += 1;
+       return e;
+}
+
+void sandbox_ObjectRemove(entity e)
+{
+       sandbox_ObjectAttach_Remove(e); // detach child objects
+
+       // if the object being removed has been selected for attachment by a player, unset it
+       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it.object_attach == e, LAMBDA(it.object_attach = NULL));
+
+       if(e.material)  {       strunzone(e.material);  e.material = string_null;       }
+       if(e.crypto_idfp)       {       strunzone(e.crypto_idfp);       e.crypto_idfp = string_null;    }
+       if(e.netname)   {       strunzone(e.netname);   e.netname = string_null;        }
+       if(e.message)   {       strunzone(e.message);   e.message = string_null;        }
+       if(e.message2)  {       strunzone(e.message2);  e.message2 = string_null;       }
+       delete(e);
+       e = NULL;
+
+       object_count -= 1;
+}
+
+string port_string[MAX_STORAGE_ATTACHMENTS]; // fteqcc crashes if this isn't defined as a global
+
+string sandbox_ObjectPort_Save(entity e, bool database)
+{
+       // save object properties, and return them as a string
+       int o = 0;
+
+       // order doesn't really matter, as we're writing the file fresh
+       IL_EACH(g_sandbox_objects, it == e || it.owner == e, LAMBDA(
+               // the main object needs to be first in the array [0] with attached objects following
+               int slot, physics, solidity;
+               if(it == e) // this is the main object, place it first
+               {
+                       slot = 0;
+                       solidity = it.solid; // applied solidity is normal solidity for children
+                       physics = it.move_movetype; // applied physics are normal physics for parents
+               }
+               else if(it.owner == e) // child object, list them in order
+               {
+                       o += 1; // children start from 1
+                       slot = o;
+                       solidity = it.old_solid; // persisted solidity is normal solidity for children
+                       physics = it.old_movetype; // persisted physics are normal physics for children
+                       gettaginfo(it.owner, it.tag_index); // get the name of the tag our object is attached to, used further below
+               }
+               else
+                       continue;
+
+               // ---------------- OBJECT PROPERTY STORAGE: SAVE ----------------
+               if(slot)
+               {
+                       // properties stored only for child objects
+                       if(gettaginfo_name)
+                               port_string[slot] = strcat(port_string[slot], "\"", gettaginfo_name, "\" ");
+                       else
+                               port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+               }
+               else
+               {
+                       // properties stored only for parent objects
+                       if(database)
+                       {
+                               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", it.origin), " ");
+                               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", it.angles), " ");
+                       }
+               }
+               // properties stored for all objects
+               port_string[slot] = strcat(port_string[slot], "\"", it.model, "\" ");
+               port_string[slot] = strcat(port_string[slot], ftos(it.skin), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(it.alpha), " ");
+               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", it.colormod), " ");
+               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", it.glowmod), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(it.frame), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(it.scale), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(solidity), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(physics), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(it.damageforcescale), " ");
+               if(it.material)
+                       port_string[slot] = strcat(port_string[slot], "\"", it.material, "\" ");
+               else
+                       port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+               if(database)
+               {
+                       // properties stored only for the database
+                       if(it.crypto_idfp)
+                               port_string[slot] = strcat(port_string[slot], "\"", it.crypto_idfp, "\" ");
+                       else
+                               port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+                       port_string[slot] = strcat(port_string[slot], "\"", e.netname, "\" ");
+                       port_string[slot] = strcat(port_string[slot], "\"", e.message, "\" ");
+                       port_string[slot] = strcat(port_string[slot], "\"", e.message2, "\" ");
+               }
+       ));
+
+       // now apply the array to a simple string, with the ; symbol separating objects
+       string s = "";
+       for(int j = 0; j <= MAX_STORAGE_ATTACHMENTS; ++j)
+       {
+               if(port_string[j])
+                       s = strcat(s, port_string[j], "; ");
+               port_string[j] = string_null; // fully clear the string
+       }
+
+       return s;
+}
+
+entity sandbox_ObjectPort_Load(entity this, string s, float database)
+{
+       // load object properties, and spawn a new object with them
+       float n, i;
+       entity e = NULL, parent = NULL;
+
+       // separate objects between the ; symbols
+       n = tokenizebyseparator(s, "; ");
+       for(i = 0; i < n; ++i)
+               port_string[i] = argv(i);
+
+       // now separate and apply the properties of each object
+       for(i = 0; i < n; ++i)
+       {
+               float argv_num;
+               string tagname = string_null;
+               argv_num = 0;
+               tokenize_console(port_string[i]);
+               e = sandbox_ObjectSpawn(this, database);
+
+               // ---------------- OBJECT PROPERTY STORAGE: LOAD ----------------
+               if(i)
+               {
+                       // properties stored only for child objects
+                       if(argv(argv_num) != "")        tagname = argv(argv_num);       else tagname = string_null;     ++argv_num;
+               }
+               else
+               {
+                       // properties stored only for parent objects
+                       if(database)
+                       {
+                               setorigin(e, stov(argv(argv_num)));     ++argv_num;
+                               e.angles = stov(argv(argv_num));        ++argv_num;
+                       }
+                       parent = e; // mark parent objects as such
+               }
+               // properties stored for all objects
+               _setmodel(e, argv(argv_num));   ++argv_num;
+               e.skin = stof(argv(argv_num));  ++argv_num;
+               e.alpha = stof(argv(argv_num)); ++argv_num;
+               e.colormod = stov(argv(argv_num));      ++argv_num;
+               e.glowmod = stov(argv(argv_num));       ++argv_num;
+               e.frame = stof(argv(argv_num)); ++argv_num;
+               sandbox_ObjectEdit_Scale(e, stof(argv(argv_num)));      ++argv_num;
+               e.solid = e.old_solid = stof(argv(argv_num));   ++argv_num;
+               e.old_movetype = stof(argv(argv_num));  ++argv_num;
+               set_movetype(e, e.old_movetype);
+               e.damageforcescale = stof(argv(argv_num));      ++argv_num;
+               if(e.material)  strunzone(e.material);  if(argv(argv_num) != "")        e.material = strzone(argv(argv_num));   else    e.material = string_null;       ++argv_num;
+               if(database)
+               {
+                       // properties stored only for the database
+                       if(e.crypto_idfp)       strunzone(e.crypto_idfp);       if(argv(argv_num) != "")        e.crypto_idfp = strzone(argv(argv_num));        else    e.crypto_idfp = string_null;    ++argv_num;
+                       if(e.netname)   strunzone(e.netname);   e.netname = strzone(argv(argv_num));    ++argv_num;
+                       if(e.message)   strunzone(e.message);   e.message = strzone(argv(argv_num));    ++argv_num;
+                       if(e.message2)  strunzone(e.message2);  e.message2 = strzone(argv(argv_num));   ++argv_num;
+               }
+
+               // attach last
+               if(i)
+                       sandbox_ObjectAttach_Set(e, parent, tagname);
+       }
+
+       for(i = 0; i <= MAX_STORAGE_ATTACHMENTS; ++i)
+               port_string[i] = string_null; // fully clear the string
+
+       return e;
+}
+
+void sandbox_Database_Save()
+{
+       // saves all objects to the database file
+       string file_name;
+       float file_get;
+
+       file_name = strcat("sandbox/storage_", autocvar_g_sandbox_storage_name, "_", GetMapname(), ".txt");
+       file_get = fopen(file_name, FILE_WRITE);
+       fputs(file_get, strcat("// sandbox storage \"", autocvar_g_sandbox_storage_name, "\" for map \"", GetMapname(), "\" last updated ", strftime(true, "%d-%m-%Y %H:%M:%S")));
+       fputs(file_get, strcat(" containing ", ftos(object_count), " objects\n"));
+
+       IL_EACH(g_sandbox_objects, !it.owner, // attached objects are persisted separately, ignore them here
+       {
+               // use a line of text for each object, listing all properties
+               fputs(file_get, strcat(sandbox_ObjectPort_Save(it, true), "\n"));
+       });
+       fclose(file_get);
+}
+
+void sandbox_Database_Load()
+{
+       // loads all objects from the database file
+       string file_read, file_name;
+       float file_get, i;
+
+       file_name = strcat("sandbox/storage_", autocvar_g_sandbox_storage_name, "_", GetMapname(), ".txt");
+       file_get = fopen(file_name, FILE_READ);
+       if(file_get < 0)
+       {
+               if(autocvar_g_sandbox_info > 0)
+                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7could not find storage file ^3", file_name, "^7, no objects were loaded\n"));
+       }
+       else
+       {
+               for (;;)
+               {
+                       file_read = fgets(file_get);
+                       if(file_read == "")
+                               break;
+                       if(substring(file_read, 0, 2) == "//")
+                               continue;
+                       if(substring(file_read, 0, 1) == "#")
+                               continue;
+
+                       entity e;
+                       e = sandbox_ObjectPort_Load(NULL, file_read, true);
+
+                       if(e.material)
+                       {
+                               // since objects are being loaded for the first time, precache material sounds for each
+                               for (i = 1; i <= 5; i++) // 5 sounds in total
+                                       precache_sound(strcat("object/impact_", e.material, "_", ftos(i), ".wav"));
+                       }
+               }
+               if(autocvar_g_sandbox_info > 0)
+                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7successfully loaded storage file ^3", file_name, "\n"));
+       }
+       fclose(file_get);
+}
+
+MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
+{
+       if(MUTATOR_RETURNVALUE) // command was already handled?
+               return;
+
+       entity player = M_ARGV(0, entity);
+       string cmd_name = M_ARGV(1, string);
+       int cmd_argc = M_ARGV(2, int);
+
+       if(cmd_name == "g_sandbox")
+       {
+               if(autocvar_g_sandbox_readonly)
+               {
+                       print_to(player, "^2SANDBOX - INFO: ^7Sandbox mode is active, but in read-only mode. Sandbox commands cannot be used");
+                       return true;
+               }
+               if(cmd_argc < 2)
+               {
+                       print_to(player, "^2SANDBOX - INFO: ^7Sandbox mode is active. For usage information, type 'sandbox help'");
+                       return true;
+               }
+
+               switch(argv(1))
+               {
+                       entity e;
+                       int j;
+                       string s;
+
+                       // ---------------- COMMAND: HELP ----------------
+                       case "help":
+                               print_to(player, "You can use the following sandbox commands:");
+                               print_to(player, "^7\"^2object_spawn ^3models/foo/bar.md3^7\" spawns a new object in front of the player, and gives it the specified model");
+                               print_to(player, "^7\"^2object_remove^7\" removes the object the player is looking at. Players can only remove their own objects");
+                               print_to(player, "^7\"^2object_duplicate ^3value^7\" duplicates the object, if the player has copying rights over the original");
+                               print_to(player, "^3copy value ^7- copies the properties of the object to the specified client cvar");
+                               print_to(player, "^3paste value ^7- spawns an object with the given properties. Properties or cvars must be specified as follows; eg1: \"0 1 2 ...\", eg2: \"$cl_cvar\"");
+                               print_to(player, "^7\"^2object_attach ^3property value^7\" attaches one object to another. Players can only attach their own objects");
+                               print_to(player, "^3get ^7- selects the object you are facing as the object to be attached");
+                               print_to(player, "^3set value ^7- attaches the previously selected object to the object you are facing, on the specified bone");
+                               print_to(player, "^3remove ^7- detaches all objects from the object you are facing");
+                               print_to(player, "^7\"^2object_edit ^3property value^7\" edits the given property of the object. Players can only edit their own objects");
+                               print_to(player, "^3skin value ^7- changes the skin of the object");
+                               print_to(player, "^3alpha value ^7- sets object transparency");
+                               print_to(player, "^3colormod \"value_x value_y value_z\" ^7- main object color");
+                               print_to(player, "^3glowmod \"value_x value_y value_z\" ^7- glow object color");
+                               print_to(player, "^3frame value ^7- object animation frame, for self-animated models");
+                               print_to(player, "^3scale value ^7- changes object scale. 0.5 is half size and 2 is double size");
+                               print_to(player, "^3solidity value ^7- object collisions, 0 = non-solid, 1 = solid");
+                               print_to(player, "^3physics value ^7- object physics, 0 = static, 1 = movable, 2 = physical");
+                               print_to(player, "^3force value ^7- amount of force applied to objects that are shot");
+                               print_to(player, "^3material value ^7- sets the material of the object. Default materials are: metal, stone, wood, flesh");
+                               print_to(player, "^7\"^2object_claim^7\" sets the player as the owner of the object, if he has the right to edit it");
+                               print_to(player, "^7\"^2object_info ^3value^7\" shows public information about the object");
+                               print_to(player, "^3object ^7- prints general information about the object, such as owner and creation / editing date");
+                               print_to(player, "^3mesh ^7- prints information about the object's mesh, including skeletal bones");
+                               print_to(player, "^3attachments ^7- prints information about the object's attachments");
+                               print_to(player, "^7The ^1drag object ^7key can be used to grab and carry objects. Players can only grab their own objects");
+                               return true;
+
+                       // ---------------- COMMAND: OBJECT, SPAWN ----------------
+                       case "object_spawn":
+                               if(time < player.object_flood)
+                               {
+                                       print_to(player, strcat("^1SANDBOX - WARNING: ^7Flood protection active. Please wait ^3", ftos(player.object_flood - time), " ^7seconds beofore spawning another object"));
+                                       return true;
+                               }
+                               player.object_flood = time + autocvar_g_sandbox_editor_flood;
+                               if(object_count >= autocvar_g_sandbox_editor_maxobjects)
+                               {
+                                       print_to(player, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
+                                       return true;
+                               }
+                               if(cmd_argc < 3)
+                               {
+                                       print_to(player, "^1SANDBOX - WARNING: ^7Attempted to spawn an object without specifying a model. Please specify the path to your model file after the 'object_spawn' command");
+                                       return true;
+                               }
+                               if (!(fexists(argv(2))))
+                               {
+                                       print_to(player, "^1SANDBOX - WARNING: ^7Attempted to spawn an object with a non-existent model. Make sure the path to your model file is correct");
+                                       return true;
+                               }
+
+                               e = sandbox_ObjectSpawn(player, false);
+                               _setmodel(e, argv(2));
+
+                               if(autocvar_g_sandbox_info > 0)
+                                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " spawned an object at origin ^3", vtos(e.origin), "\n"));
+                               return true;
+
+                       // ---------------- COMMAND: OBJECT, REMOVE ----------------
+                       case "object_remove":
+                               e = sandbox_ObjectEdit_Get(player, true);
+                               if(e != NULL)
+                               {
+                                       if(autocvar_g_sandbox_info > 0)
+                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " removed an object at origin ^3", vtos(e.origin), "\n"));
+                                       sandbox_ObjectRemove(e);
+                                       return true;
+                               }
+
+                               print_to(player, "^1SANDBOX - WARNING: ^7Object could not be removed. Make sure you are facing an object that you have edit rights over");
+                               return true;
+
+                       // ---------------- COMMAND: OBJECT, DUPLICATE ----------------
+                       case "object_duplicate":
+                               switch(argv(2))
+                               {
+                                       case "copy":
+                                               // copies customizable properties of the selected object to the clipboard cvar
+                                               e = sandbox_ObjectEdit_Get(player, autocvar_g_sandbox_editor_free); // can we copy objects we can't edit?
+                                               if(e != NULL)
+                                               {
+                                                       s = sandbox_ObjectPort_Save(e, false);
+                                                       s = strreplace("\"", "\\\"", s);
+                                                       stuffcmd(player, strcat("set ", argv(3), " \"", s, "\""));
+
+                                                       print_to(player, "^2SANDBOX - INFO: ^7Object copied to clipboard");
+                                                       return true;
+                                               }
+                                               print_to(player, "^1SANDBOX - WARNING: ^7Object could not be copied. Make sure you are facing an object that you have copy rights over");
+                                               return true;
+
+                                       case "paste":
+                                               // spawns a new object using the properties in the player's clipboard cvar
+                                               if(time < player.object_flood)
+                                               {
+                                                       print_to(player, strcat("^1SANDBOX - WARNING: ^7Flood protection active. Please wait ^3", ftos(player.object_flood - time), " ^7seconds beofore spawning another object"));
+                                                       return true;
+                                               }
+                                               player.object_flood = time + autocvar_g_sandbox_editor_flood;
+                                               if(argv(3) == "") // no object in clipboard
+                                               {
+                                                       print_to(player, "^1SANDBOX - WARNING: ^7No object in clipboard. You must copy an object before you can paste it");
+                                                       return true;
+                                               }
+                                               if(object_count >= autocvar_g_sandbox_editor_maxobjects)
+                                               {
+                                                       print_to(player, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
+                                                       return true;
+                                               }
+                                               e = sandbox_ObjectPort_Load(player, argv(3), false);
+
+                                               print_to(player, "^2SANDBOX - INFO: ^7Object pasted successfully");
+                                               if(autocvar_g_sandbox_info > 0)
+                                                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " pasted an object at origin ^3", vtos(e.origin), "\n"));
+                                               return true;
+                               }
+                               return true;
+
+                       // ---------------- COMMAND: OBJECT, ATTACH ----------------
+                       case "object_attach":
+                               switch(argv(2))
+                               {
+                                       case "get":
+                                               // select e as the object as meant to be attached
+                                               e = sandbox_ObjectEdit_Get(player, true);
+                                               if(e != NULL)
+                                               {
+                                                       player.object_attach = e;
+                                                       print_to(player, "^2SANDBOX - INFO: ^7Object selected for attachment");
+                                                       return true;
+                                               }
+                                               print_to(player, "^1SANDBOX - WARNING: ^7Object could not be selected for attachment. Make sure you are facing an object that you have edit rights over");
+                                               return true;
+                                       case "set":
+                                               if(player.object_attach == NULL)
+                                               {
+                                                       print_to(player, "^1SANDBOX - WARNING: ^7No object selected for attachment. Please select an object to be attached first.");
+                                                       return true;
+                                               }
+
+                                               // attaches the previously selected object to e
+                                               e = sandbox_ObjectEdit_Get(player, true);
+                                               if(e != NULL)
+                                               {
+                                                       sandbox_ObjectAttach_Set(player.object_attach, e, argv(3));
+                                                       player.object_attach = NULL; // object was attached, no longer keep it scheduled for attachment
+                                                       print_to(player, "^2SANDBOX - INFO: ^7Object attached successfully");
+                                                       if(autocvar_g_sandbox_info > 1)
+                                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " attached objects at origin ^3", vtos(e.origin), "\n"));
+                                                       return true;
+                                               }
+                                               print_to(player, "^1SANDBOX - WARNING: ^7Object could not be attached to the parent. Make sure you are facing an object that you have edit rights over");
+                                               return true;
+                                       case "remove":
+                                               // removes e if it was attached
+                                               e = sandbox_ObjectEdit_Get(player, true);
+                                               if(e != NULL)
+                                               {
+                                                       sandbox_ObjectAttach_Remove(e);
+                                                       print_to(player, "^2SANDBOX - INFO: ^7Child objects detached successfully");
+                                                       if(autocvar_g_sandbox_info > 1)
+                                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " detached objects at origin ^3", vtos(e.origin), "\n"));
+                                                       return true;
+                                               }
+                                               print_to(player, "^1SANDBOX - WARNING: ^7Child objects could not be detached. Make sure you are facing an object that you have edit rights over");
+                                               return true;
+                               }
+                               return true;
+
+                       // ---------------- COMMAND: OBJECT, EDIT ----------------
+                       case "object_edit":
+                               if(argv(2) == "")
+                               {
+                                       print_to(player, "^1SANDBOX - WARNING: ^7Too few parameters. You must specify a property to edit");
+                                       return true;
+                               }
+
+                               e = sandbox_ObjectEdit_Get(player, true);
+                               if(e != NULL)
+                               {
+                                       switch(argv(2))
+                                       {
+                                               case "skin":
+                                                       e.skin = stof(argv(3));
+                                                       break;
+                                               case "alpha":
+                                                       e.alpha = stof(argv(3));
+                                                       break;
+                                               case "color_main":
+                                                       e.colormod = stov(argv(3));
+                                                       break;
+                                               case "color_glow":
+                                                       e.glowmod = stov(argv(3));
+                                                       break;
+                                               case "frame":
+                                                       e.frame = stof(argv(3));
+                                                       break;
+                                               case "scale":
+                                                       sandbox_ObjectEdit_Scale(e, stof(argv(3)));
+                                                       break;
+                                               case "solidity":
+                                                       switch(argv(3))
+                                                       {
+                                                               case "0": // non-solid
+                                                                       e.solid = SOLID_TRIGGER;
+                                                                       break;
+                                                               case "1": // solid
+                                                                       e.solid = SOLID_BBOX;
+                                                                       break;
+                                                               default:
+                                                                       break;
+                                                       }
+                                               case "physics":
+                                                       switch(argv(3))
+                                                       {
+                                                               case "0": // static
+                                                                       set_movetype(e, MOVETYPE_NONE);
+                                                                       break;
+                                                               case "1": // movable
+                                                                       set_movetype(e, MOVETYPE_TOSS);
+                                                                       break;
+                                                               case "2": // physical
+                                                                       set_movetype(e, MOVETYPE_PHYSICS);
+                                                                       break;
+                                                               default:
+                                                                       break;
+                                                       }
+                                                       break;
+                                               case "force":
+                                                       e.damageforcescale = stof(argv(3));
+                                                       break;
+                                               case "material":
+                                                       if(e.material)  strunzone(e.material);
+                                                       if(argv(3))
+                                                       {
+                                                               for (j = 1; j <= 5; j++) // precache material sounds, 5 in total
+                                                                       precache_sound(strcat("object/impact_", argv(3), "_", ftos(j), ".wav"));
+                                                               e.material = strzone(argv(3));
+                                                       }
+                                                       else
+                                                               e.material = string_null; // no material
+                                                       break;
+                                               default:
+                                                       print_to(player, "^1SANDBOX - WARNING: ^7Invalid object property. For usage information, type 'sandbox help'");
+                                                       return true;
+                                       }
+
+                                       // update last editing time
+                                       if(e.message2)  strunzone(e.message2);
+                                       e.message2 = strzone(strftime(true, "%d-%m-%Y %H:%M:%S"));
+
+                                       if(autocvar_g_sandbox_info > 1)
+                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", player.netname, " edited property ^3", argv(2), " ^7of an object at origin ^3", vtos(e.origin), "\n"));
+                                       return true;
+                               }
+
+                               print_to(player, "^1SANDBOX - WARNING: ^7Object could not be edited. Make sure you are facing an object that you have edit rights over");
+                               return true;
+
+                       // ---------------- COMMAND: OBJECT, CLAIM ----------------
+                       case "object_claim":
+                               // if the player can edit an object but is not its owner, this can be used to claim that object
+                               if(player.crypto_idfp == "")
+                               {
+                                       print_to(player, "^1SANDBOX - WARNING: ^7You do not have a player UID, and cannot claim objects");
+                                       return true;
+                               }
+                               e = sandbox_ObjectEdit_Get(player, true);
+                               if(e != NULL)
+                               {
+                                       // update the owner's name
+                                       // Do this before checking if you're already the owner and skipping if such, so we
+                                       // also update the player's nickname if he changed it (but has the same player UID)
+                                       if(e.netname != player.netname)
+                                       {
+                                               if(e.netname)   strunzone(e.netname);
+                                               e.netname = strzone(player.netname);
+                                               print_to(player, "^2SANDBOX - INFO: ^7Object owner name updated");
+                                       }
+
+                                       if(e.crypto_idfp == player.crypto_idfp)
+                                       {
+                                               print_to(player, "^2SANDBOX - INFO: ^7Object is already yours, nothing to claim");
+                                               return true;
+                                       }
+
+                                       if(e.crypto_idfp)       strunzone(e.crypto_idfp);
+                                       e.crypto_idfp = strzone(player.crypto_idfp);
+
+                                       print_to(player, "^2SANDBOX - INFO: ^7Object claimed successfully");
+                               }
+                               print_to(player, "^1SANDBOX - WARNING: ^7Object could not be claimed. Make sure you are facing an object that you have edit rights over");
+                               return true;
+
+                       // ---------------- COMMAND: OBJECT, INFO ----------------
+                       case "object_info":
+                               // prints public information about the object to the player
+                               e = sandbox_ObjectEdit_Get(player, false);
+                               if(e != NULL)
+                               {
+                                       switch(argv(2))
+                                       {
+                                               case "object":
+                                                       print_to(player, strcat("^2SANDBOX - INFO: ^7Object is owned by \"^7", e.netname, "^7\", created \"^3", e.message, "^7\", last edited \"^3", e.message2, "^7\""));
+                                                       return true;
+                                               case "mesh":
+                                                       s = "";
+                                                       FOR_EACH_TAG(e)
+                                                               s = strcat(s, "^7\"^5", gettaginfo_name, "^7\", ");
+                                                       print_to(player, strcat("^2SANDBOX - INFO: ^7Object mesh is \"^3", e.model, "^7\" at animation frame ^3", ftos(e.frame), " ^7containing the following tags: ", s));
+                                                       return true;
+                                               case "attachments":
+                                                       // this should show the same info as 'mesh' but for attachments
+                                                       s = "";
+                                                       j = 0;
+                                                       IL_EACH(g_sandbox_objects, it.owner == e,
+                                                       {
+                                                               ++j; // start from 1
+                                                               gettaginfo(e, it.tag_index);
+                                                               s = strcat(s, "^1attachment ", ftos(j), "^7 has mesh \"^3", it.model, "^7\" at animation frame ^3", ftos(it.frame));
+                                                               s = strcat(s, "^7 and is attached to bone \"^5", gettaginfo_name, "^7\", ");
+                                                       });
+                                                       if(j) // object contains attachments
+                                                               print_to(player, strcat("^2SANDBOX - INFO: ^7Object contains the following ^1", ftos(j), "^7 attachment(s): ", s));
+                                                       else
+                                                               print_to(player, "^2SANDBOX - INFO: ^7Object contains no attachments");
+                                                       return true;
+                                       }
+                               }
+                               print_to(player, "^1SANDBOX - WARNING: ^7No information could be found. Make sure you are facing an object");
+                               return true;
+
+                       // ---------------- COMMAND: DEFAULT ----------------
+                       default:
+                               print_to(player, "Invalid command. For usage information, type 'sandbox help'");
+                               return true;
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(sandbox, SV_StartFrame)
+{
+       if(!autocvar_g_sandbox_storage_autosave)
+               return;
+       if(time < autosave_time)
+               return;
+       autosave_time = time + autocvar_g_sandbox_storage_autosave;
+
+       sandbox_Database_Save();
+
+       return true;
+}
diff --git a/qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qh b/qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qh
new file mode 100644 (file)
index 0000000..f6a0afd
--- /dev/null
@@ -0,0 +1,4 @@
+#pragma once
+
+IntrusiveList g_sandbox_objects;
+STATIC_INIT(g_sandbox_objects) { g_sandbox_objects = IL_NEW(); }
index b7d3af7f4dd3124e9f5521daa0e814a386e9d357..fe3a6ebc5d612cd64ff0fd96d5df502f956176d2 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/spawn_near_teammate/spawn_near_teammate.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qc>
+#endif
index 5f53e95c885857a293ecdc19b98f1415a5d1db85..b34f8f8f164c22c2bb724817ee2ca77fc3710453 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/spawn_near_teammate/spawn_near_teammate.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/spawn_near_teammate/module.inc b/qcsrc/common/mutators/mutator/spawn_near_teammate/module.inc
deleted file mode 100644 (file)
index f88a768..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "spawn_near_teammate.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/spawn_near_teammate/spawn_near_teammate.qc b/qcsrc/common/mutators/mutator/spawn_near_teammate/spawn_near_teammate.qc
deleted file mode 100644 (file)
index 20f07e9..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-#ifdef IMPLEMENTATION
-
-float autocvar_g_spawn_near_teammate_distance;
-int autocvar_g_spawn_near_teammate_ignore_spawnpoint;
-float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
-float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
-int autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health;
-bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath;
-
-REGISTER_MUTATOR(spawn_near_teammate, cvar("g_spawn_near_teammate"));
-
-.entity msnt_lookat;
-
-.float msnt_timer;
-.vector msnt_deathloc;
-
-.float cvar_cl_spawn_near_teammate;
-
-MUTATOR_HOOKFUNCTION(spawn_near_teammate, Spawn_Score)
-{
-       entity player = M_ARGV(0, entity);
-       entity spawn_spot = M_ARGV(1, entity);
-       vector spawn_score = M_ARGV(2, vector);
-
-       if(autocvar_g_spawn_near_teammate_ignore_spawnpoint == 1 || (autocvar_g_spawn_near_teammate_ignore_spawnpoint == 2 && player.cvar_cl_spawn_near_teammate))
-               return;
-
-       spawn_spot.msnt_lookat = NULL;
-
-       if(!teamplay)
-               return;
-
-       RandomSelection_Init();
-       FOREACH_CLIENT(IS_PLAYER(it) && it != player && SAME_TEAM(it, player) && !IS_DEAD(it), LAMBDA(
-               if(vdist(spawn_spot.origin - it.origin, >, autocvar_g_spawn_near_teammate_distance))
-                       continue;
-               if(vdist(spawn_spot.origin - it.origin, <, 48))
-                       continue;
-               if(!checkpvs(spawn_spot.origin, it))
-                       continue;
-               RandomSelection_Add(it, 0, string_null, 1, 1);
-       ));
-
-       if(RandomSelection_chosen_ent)
-       {
-               spawn_spot.msnt_lookat = RandomSelection_chosen_ent;
-               spawn_score.x += SPAWN_PRIO_NEAR_TEAMMATE_FOUND;
-       }
-       else if(player.team == spawn_spot.team)
-               spawn_score.x += SPAWN_PRIO_NEAR_TEAMMATE_SAMETEAM; // prefer same team, if we can't find a spawn near teammate
-
-       M_ARGV(2, vector) = spawn_score;
-}
-
-MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerSpawn)
-{
-       if(!teamplay) { return; }
-       entity player = M_ARGV(0, entity);
-       entity spawn_spot = M_ARGV(1, entity);
-
-       int num_red = 0, num_blue = 0, num_yellow = 0, num_pink = 0;
-       FOREACH_CLIENT(IS_PLAYER(it),
-       {
-               switch(it.team)
-               {
-                       case NUM_TEAM_1: ++num_red; break;
-                       case NUM_TEAM_2: ++num_blue; break;
-                       case NUM_TEAM_3: ++num_yellow; break;
-                       case NUM_TEAM_4: ++num_pink; break;
-               }
-       });
-
-       if(num_red == 1 || num_blue == 1 || num_yellow == 1 || num_pink == 1)
-               return; // at least 1 team has only 1 player, let's not give the bigger team too much of an advantage!
-
-       // Note: when entering this, fixangle is already set.
-       if(autocvar_g_spawn_near_teammate_ignore_spawnpoint == 1 || (autocvar_g_spawn_near_teammate_ignore_spawnpoint == 2 && player.cvar_cl_spawn_near_teammate))
-       {
-               if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death)
-                       player.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
-
-               entity best_mate = NULL;
-               vector best_spot = '0 0 0';
-               float pc = 0, best_dist = 0, dist = 0;
-               FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
-                       if((autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health >= 0 && it.health >= autocvar_g_balance_health_regenstable) || autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health == 0)
-                       if(!IS_DEAD(it))
-                       if(it.msnt_timer < time)
-                       if(SAME_TEAM(player, it))
-                       if(time > it.spawnshieldtime) // spawn shielding
-                       if(!forbidWeaponUse(it))
-                       if(STAT(FROZEN, it) == 0)
-                       if(it != player)
-                       {
-                               tracebox(it.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - '0 0 100', MOVE_NOMONSTERS, it);
-                               if(trace_fraction != 1.0)
-                               if(!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
-                               {
-                                       pc = pointcontents(trace_endpos + '0 0 1');
-                                       if(pc == CONTENT_EMPTY)
-                                       {
-                                               if(vdist(it.velocity, >, 5))
-                                                       fixedmakevectors(vectoangles(it.velocity));
-                                               else
-                                                       fixedmakevectors(it.angles);
-
-                                               for(pc = 0; pc < 4; ++pc) // test 4 diffrent spots close to mate
-                                               {
-                                                       switch(pc)
-                                                       {
-                                                               case 0:
-                                                                       tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin + v_right * 128, MOVE_NOMONSTERS, it);
-                                                                       break;
-                                                               case 1:
-                                                                       tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - v_right * 128 , MOVE_NOMONSTERS, it);
-                                                                       break;
-                                                               case 2:
-                                                                       tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin + v_right * 128 - v_forward * 64, MOVE_NOMONSTERS, it);
-                                                                       break;
-                                                               case 3:
-                                                                       tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - v_right * 128 - v_forward * 64, MOVE_NOMONSTERS, it);
-                                                                       break;
-                                                               //case 4:
-                                                                       //tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - v_forward * 128, MOVE_NOMONSTERS, it);
-                                                                       //break;
-                                                       }
-
-                                                       if(trace_fraction == 1.0)
-                                                       {
-                                                               traceline(trace_endpos + '0 0 4', trace_endpos - '0 0 100', MOVE_NOMONSTERS, it);
-                                                               if(trace_fraction != 1.0)
-                                                               {
-                                                                       if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
-                                                                       {
-                                                                               dist = vlen(trace_endpos - player.msnt_deathloc);
-                                                                               if(dist < best_dist || best_dist == 0)
-                                                                               {
-                                                                                       best_dist = dist;
-                                                                                       best_spot = trace_endpos;
-                                                                                       best_mate = it;
-                                                                               }
-                                                                       }
-                                                                       else
-                                                                       {
-                                                                               setorigin(player, trace_endpos);
-                                                                               player.angles = it.angles;
-                                                                               player.angles_z = 0; // never spawn tilted even if the spot says to
-                                                                               it.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
-                                                                               return;
-                                                                       }
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               ));
-
-               if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
-               if(best_dist)
-               {
-                       setorigin(player, best_spot);
-                       player.angles = best_mate.angles;
-                       player.angles_z = 0; // never spawn tilted even if the spot says to
-                       best_mate.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
-               }
-       }
-       else if(spawn_spot.msnt_lookat)
-       {
-               player.angles = vectoangles(spawn_spot.msnt_lookat.origin - player.origin);
-               player.angles_x = -player.angles.x;
-               player.angles_z = 0; // never spawn tilted even if the spot says to
-               /*
-               sprint(player, "You should be looking at ", spawn_spot.msnt_lookat.netname, "^7.\n");
-               sprint(player, "distance: ", vtos(spawn_spot.msnt_lookat.origin - player.origin), "\n");
-               sprint(player, "angles: ", vtos(player.angles), "\n");
-               */
-       }
-}
-
-MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerDies)
-{
-       entity frag_target = M_ARGV(0, entity);
-
-       frag_target.msnt_deathloc = frag_target.origin;
-}
-
-REPLICATE(cvar_cl_spawn_near_teammate, bool, "cl_spawn_near_teammate");
-
-#endif
diff --git a/qcsrc/common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qc b/qcsrc/common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qc
new file mode 100644 (file)
index 0000000..fb14f27
--- /dev/null
@@ -0,0 +1,188 @@
+#include "sv_spawn_near_teammate.qh"
+
+float autocvar_g_spawn_near_teammate_distance;
+int autocvar_g_spawn_near_teammate_ignore_spawnpoint;
+float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
+float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
+int autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health;
+bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath;
+
+REGISTER_MUTATOR(spawn_near_teammate, cvar("g_spawn_near_teammate"));
+
+.entity msnt_lookat;
+
+.float msnt_timer;
+.vector msnt_deathloc;
+
+.float cvar_cl_spawn_near_teammate;
+
+MUTATOR_HOOKFUNCTION(spawn_near_teammate, Spawn_Score)
+{
+       entity player = M_ARGV(0, entity);
+       entity spawn_spot = M_ARGV(1, entity);
+       vector spawn_score = M_ARGV(2, vector);
+
+       if(autocvar_g_spawn_near_teammate_ignore_spawnpoint == 1 || (autocvar_g_spawn_near_teammate_ignore_spawnpoint == 2 && player.cvar_cl_spawn_near_teammate))
+               return;
+
+       spawn_spot.msnt_lookat = NULL;
+
+       if(!teamplay)
+               return;
+
+       RandomSelection_Init();
+       FOREACH_CLIENT(IS_PLAYER(it) && it != player && SAME_TEAM(it, player) && !IS_DEAD(it), LAMBDA(
+               if(vdist(spawn_spot.origin - it.origin, >, autocvar_g_spawn_near_teammate_distance))
+                       continue;
+               if(vdist(spawn_spot.origin - it.origin, <, 48))
+                       continue;
+               if(!checkpvs(spawn_spot.origin, it))
+                       continue;
+               RandomSelection_Add(it, 0, string_null, 1, 1);
+       ));
+
+       if(RandomSelection_chosen_ent)
+       {
+               spawn_spot.msnt_lookat = RandomSelection_chosen_ent;
+               spawn_score.x += SPAWN_PRIO_NEAR_TEAMMATE_FOUND;
+       }
+       else if(player.team == spawn_spot.team)
+               spawn_score.x += SPAWN_PRIO_NEAR_TEAMMATE_SAMETEAM; // prefer same team, if we can't find a spawn near teammate
+
+       M_ARGV(2, vector) = spawn_score;
+}
+
+MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerSpawn)
+{
+       if(!teamplay) { return; }
+       entity player = M_ARGV(0, entity);
+       entity spawn_spot = M_ARGV(1, entity);
+
+       int num_red = 0, num_blue = 0, num_yellow = 0, num_pink = 0;
+       FOREACH_CLIENT(IS_PLAYER(it),
+       {
+               switch(it.team)
+               {
+                       case NUM_TEAM_1: ++num_red; break;
+                       case NUM_TEAM_2: ++num_blue; break;
+                       case NUM_TEAM_3: ++num_yellow; break;
+                       case NUM_TEAM_4: ++num_pink; break;
+               }
+       });
+
+       if(num_red == 1 || num_blue == 1 || num_yellow == 1 || num_pink == 1)
+               return; // at least 1 team has only 1 player, let's not give the bigger team too much of an advantage!
+
+       // Note: when entering this, fixangle is already set.
+       if(autocvar_g_spawn_near_teammate_ignore_spawnpoint == 1 || (autocvar_g_spawn_near_teammate_ignore_spawnpoint == 2 && player.cvar_cl_spawn_near_teammate))
+       {
+               if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death)
+                       player.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
+
+               entity best_mate = NULL;
+               vector best_spot = '0 0 0';
+               float pc = 0, best_dist = 0, dist = 0;
+               FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
+                       if((autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health >= 0 && it.health >= autocvar_g_balance_health_regenstable) || autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health == 0)
+                       if(!IS_DEAD(it))
+                       if(it.msnt_timer < time)
+                       if(SAME_TEAM(player, it))
+                       if(time > it.spawnshieldtime) // spawn shielding
+                       if(!forbidWeaponUse(it))
+                       if(STAT(FROZEN, it) == 0)
+                       if(it != player)
+                       {
+                               tracebox(it.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - '0 0 100', MOVE_NOMONSTERS, it);
+                               if(trace_fraction != 1.0)
+                               if(!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
+                               {
+                                       pc = pointcontents(trace_endpos + '0 0 1');
+                                       if(pc == CONTENT_EMPTY)
+                                       {
+                                               if(vdist(it.velocity, >, 5))
+                                                       fixedmakevectors(vectoangles(it.velocity));
+                                               else
+                                                       fixedmakevectors(it.angles);
+
+                                               for(pc = 0; pc < 4; ++pc) // test 4 diffrent spots close to mate
+                                               {
+                                                       switch(pc)
+                                                       {
+                                                               case 0:
+                                                                       tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin + v_right * 128, MOVE_NOMONSTERS, it);
+                                                                       break;
+                                                               case 1:
+                                                                       tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - v_right * 128 , MOVE_NOMONSTERS, it);
+                                                                       break;
+                                                               case 2:
+                                                                       tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin + v_right * 128 - v_forward * 64, MOVE_NOMONSTERS, it);
+                                                                       break;
+                                                               case 3:
+                                                                       tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - v_right * 128 - v_forward * 64, MOVE_NOMONSTERS, it);
+                                                                       break;
+                                                               //case 4:
+                                                                       //tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - v_forward * 128, MOVE_NOMONSTERS, it);
+                                                                       //break;
+                                                       }
+
+                                                       if(trace_fraction == 1.0)
+                                                       {
+                                                               traceline(trace_endpos + '0 0 4', trace_endpos - '0 0 100', MOVE_NOMONSTERS, it);
+                                                               if(trace_fraction != 1.0)
+                                                               {
+                                                                       if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
+                                                                       {
+                                                                               dist = vlen(trace_endpos - player.msnt_deathloc);
+                                                                               if(dist < best_dist || best_dist == 0)
+                                                                               {
+                                                                                       best_dist = dist;
+                                                                                       best_spot = trace_endpos;
+                                                                                       best_mate = it;
+                                                                               }
+                                                                       }
+                                                                       else
+                                                                       {
+                                                                               setorigin(player, trace_endpos);
+                                                                               player.angles = it.angles;
+                                                                               player.angles_z = 0; // never spawn tilted even if the spot says to
+                                                                               it.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
+                                                                               return;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               ));
+
+               if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
+               if(best_dist)
+               {
+                       setorigin(player, best_spot);
+                       player.angles = best_mate.angles;
+                       player.angles_z = 0; // never spawn tilted even if the spot says to
+                       best_mate.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
+               }
+       }
+       else if(spawn_spot.msnt_lookat)
+       {
+               player.angles = vectoangles(spawn_spot.msnt_lookat.origin - player.origin);
+               player.angles_x = -player.angles.x;
+               player.angles_z = 0; // never spawn tilted even if the spot says to
+               /*
+               sprint(player, "You should be looking at ", spawn_spot.msnt_lookat.netname, "^7.\n");
+               sprint(player, "distance: ", vtos(spawn_spot.msnt_lookat.origin - player.origin), "\n");
+               sprint(player, "angles: ", vtos(player.angles), "\n");
+               */
+       }
+}
+
+MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerDies)
+{
+       entity frag_target = M_ARGV(0, entity);
+
+       frag_target.msnt_deathloc = frag_target.origin;
+}
+
+REPLICATE(cvar_cl_spawn_near_teammate, bool, "cl_spawn_near_teammate");
diff --git a/qcsrc/common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qh b/qcsrc/common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index d5005242f241344d6cdf4571994dadeedd36b4d2..262c7fcdbc82e5fdf1948de2674b7036d9659171 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/superspec/superspec.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/superspec/sv_superspec.qc>
+#endif
index b544ffc611594eb103ef3d61b27e119f83d514b3..110087b6749652c0c4b11a16850c7bebdb1036c8 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/superspec/superspec.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/superspec/sv_superspec.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/superspec/module.inc b/qcsrc/common/mutators/mutator/superspec/module.inc
deleted file mode 100644 (file)
index 8e0a998..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "superspec.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/superspec/superspec.qc b/qcsrc/common/mutators/mutator/superspec/superspec.qc
deleted file mode 100644 (file)
index 947ff01..0000000
+++ /dev/null
@@ -1,459 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(superspec, cvar("g_superspectate"));
-
-#define _SSMAGIX "SUPERSPEC_OPTIONSFILE_V1"
-#define _ISLOCAL(ent) ((edict_num(1) == (ent)) ? true : false)
-
-const float ASF_STRENGTH               = BIT(0);
-const float ASF_SHIELD                         = BIT(1);
-const float ASF_MEGA_AR                = BIT(2);
-const float ASF_MEGA_HP                = BIT(3);
-const float ASF_FLAG_GRAB              = BIT(4);
-const float ASF_OBSERVER_ONLY  = BIT(5);
-const float ASF_SHOWWHAT               = BIT(6);
-const float ASF_SSIM                   = BIT(7);
-const float ASF_FOLLOWKILLER   = BIT(8);
-const float ASF_ALL                    = 0xFFFFFF;
-.float autospec_flags;
-
-const float SSF_SILENT = 1;
-const float SSF_VERBOSE = 2;
-const float SSF_ITEMMSG = 4;
-.float superspec_flags;
-
-.string superspec_itemfilter; //"classname1 classname2 ..."
-
-bool superspec_Spectate(entity this, entity targ)
-{
-       if(Spectate(this, targ) == 1)
-           TRANSMUTE(Spectator, this);
-
-       return true;
-}
-
-void superspec_save_client_conf(entity this)
-{
-       string fn = "superspec-local.options";
-       float fh;
-
-       if (!_ISLOCAL(this))
-       {
-               if(this.crypto_idfp == "")
-                       return;
-
-               fn = sprintf("superspec-%s.options", uri_escape(this.crypto_idfp));
-       }
-
-       fh = fopen(fn, FILE_WRITE);
-       if(fh < 0)
-       {
-               LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for writing.");
-       }
-       else
-       {
-               fputs(fh, _SSMAGIX);
-               fputs(fh, "\n");
-               fputs(fh, ftos(this.autospec_flags));
-               fputs(fh, "\n");
-               fputs(fh, ftos(this.superspec_flags));
-               fputs(fh, "\n");
-               fputs(fh, this.superspec_itemfilter);
-               fputs(fh, "\n");
-               fclose(fh);
-       }
-}
-
-void superspec_msg(string _center_title, string _con_title, entity _to, string _msg, float _spamlevel)
-{
-       sprint(_to, strcat(_con_title, _msg));
-
-       if(_to.superspec_flags & SSF_SILENT)
-               return;
-
-       if(_spamlevel > 1)
-               if (!(_to.superspec_flags & SSF_VERBOSE))
-                       return;
-
-       centerprint(_to, strcat(_center_title, _msg));
-}
-
-float superspec_filteritem(entity _for, entity _item)
-{
-       float i;
-
-       if(_for.superspec_itemfilter == "")
-               return true;
-
-       if(_for.superspec_itemfilter == "")
-               return true;
-
-       float l = tokenize_console(_for.superspec_itemfilter);
-       for(i = 0; i < l; ++i)
-       {
-               if(argv(i) == _item.classname)
-                       return true;
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(superspec, ItemTouch)
-{
-       entity item = M_ARGV(0, entity);
-       entity toucher = M_ARGV(1, entity);
-
-       FOREACH_CLIENT(true, LAMBDA(
-               if(!IS_SPEC(it) && !IS_OBSERVER(it))
-                       continue;
-               if(it.superspec_flags & SSF_ITEMMSG)
-                       if(superspec_filteritem(it, item))
-                       {
-                               if(it.superspec_flags & SSF_VERBOSE)
-                                       superspec_msg("", "", it, sprintf("Player %s^7 just picked up ^3%s\n", toucher.netname, item.netname), 1);
-                               else
-                                       superspec_msg("", "", it, sprintf("Player %s^7 just picked up ^3%s\n^8(%s^8)\n", toucher.netname, item.netname, item.classname), 1);
-                               if((it.autospec_flags & ASF_SSIM) && it.enemy != toucher)
-                               {
-                                       superspec_Spectate(it, toucher);
-                                       return MUT_ITEMTOUCH_CONTINUE;
-                               }
-                       }
-
-               if((it.autospec_flags & ASF_SHIELD && item.invincible_finished) ||
-                       (it.autospec_flags & ASF_STRENGTH && item.strength_finished) ||
-                       (it.autospec_flags & ASF_MEGA_AR && item.itemdef == ITEM_ArmorMega) ||
-                       (it.autospec_flags & ASF_MEGA_HP && item.itemdef == ITEM_HealthMega) ||
-                       (it.autospec_flags & ASF_FLAG_GRAB && item.classname == "item_flag_team"))
-               {
-
-                       if((it.enemy != toucher) || IS_OBSERVER(it))
-                       {
-                               if(it.autospec_flags & ASF_OBSERVER_ONLY && !IS_OBSERVER(it))
-                               {
-                                       if(it.superspec_flags & SSF_VERBOSE)
-                                               superspec_msg("", "", it, sprintf("^8Ignored that ^7%s^8 grabbed %s^8 since the observer_only option is ON\n", toucher.netname, item.netname), 2);
-                               }
-                               else
-                               {
-                                       if(it.autospec_flags & ASF_SHOWWHAT)
-                                               superspec_msg("", "", it, sprintf("^7Following %s^7 due to picking up %s\n", toucher.netname, item.netname), 2);
-
-                                       superspec_Spectate(it, toucher);
-                               }
-                       }
-               }
-       ));
-
-       return MUT_ITEMTOUCH_CONTINUE;
-}
-
-MUTATOR_HOOKFUNCTION(superspec, SV_ParseClientCommand)
-{
-#define OPTIONINFO(flag,var,test,text,long,short) \
-    var = strcat(var, ((flag & test) ? "^2[ON]  ^7" : "^1[OFF] ^7")); \
-    var = strcat(var, text," ^7(^3 ", long, "^7 | ^3", short, " ^7)\n")
-
-       if(MUTATOR_RETURNVALUE) // command was already handled?
-               return;
-
-       entity player = M_ARGV(0, entity);
-       string cmd_name = M_ARGV(1, string);
-       int cmd_argc = M_ARGV(2, int);
-
-       if(IS_PLAYER(player))
-               return;
-
-       if(cmd_name == "superspec_itemfilter")
-       {
-               if(argv(1) == "help")
-               {
-                       string _aspeco;
-                       _aspeco = "^7 superspec_itemfilter ^3\"item_classname1 item_classname2\"^7 only show thise items when ^2superspec ^3item_message^7 is on\n";
-                       _aspeco = strcat(_aspeco, "^3 clear^7 Remove the filter (show all pickups)\n");
-                       _aspeco = strcat(_aspeco, "^3 show ^7 Display current filter\n");
-                       superspec_msg("^3superspec_itemfilter help:\n\n\n", "\n^3superspec_itemfilter help:\n", player, _aspeco, 1);
-               }
-               else if(argv(1) == "clear")
-               {
-                       if(player.superspec_itemfilter != "")
-                               strunzone(player.superspec_itemfilter);
-
-                       player.superspec_itemfilter = "";
-               }
-               else if(argv(1) == "show" || argv(1) == "")
-               {
-                       if(player.superspec_itemfilter == "")
-                       {
-                               superspec_msg("^3superspec_itemfilter^7 is ^1not^7 set", "\n^3superspec_itemfilter^7 is ^1not^7 set\n", player, "", 1);
-                               return true;
-                       }
-                       float i;
-                       float l = tokenize_console(player.superspec_itemfilter);
-                       string _msg = "";
-                       for(i = 0; i < l; ++i)
-                               _msg = strcat(_msg, "^3#", ftos(i), " ^7", argv(i), "\n");
-                               //_msg = sprintf("^3#%d^7 %s\n%s", i, _msg, argv(i));
-
-                       _msg = strcat(_msg,"\n");
-
-                       superspec_msg("^3superspec_itemfilter is:\n\n\n", "\n^3superspec_itemfilter is:\n", player, _msg, 1);
-               }
-               else
-               {
-                       if(player.superspec_itemfilter != "")
-                               strunzone(player.superspec_itemfilter);
-
-                       player.superspec_itemfilter = strzone(argv(1));
-               }
-
-               return true;
-       }
-
-       if(cmd_name == "superspec")
-       {
-               string _aspeco;
-
-               if(cmd_argc > 1)
-               {
-                       float i, _bits = 0, _start = 1;
-                       if(argv(1) == "help")
-                       {
-                               _aspeco = "use cmd superspec [option] [on|off] to set options\n\n";
-                               _aspeco = strcat(_aspeco, "^3 silent ^7(short^5 si^7) supresses ALL messages from superspectate.\n");
-                               _aspeco = strcat(_aspeco, "^3 verbose ^7(short^5 ve^7) makes superspectate print some additional information.\n");
-                               _aspeco = strcat(_aspeco, "^3 item_message ^7(short^5 im^7) makes superspectate print items that were picked up.\n");
-                               _aspeco = strcat(_aspeco, "^7    Use cmd superspec_itemfilter \"item_class1 item_class2\" to set up a filter of what to show with ^3item_message.\n");
-                               superspec_msg("^2Available Super Spectate ^3options:\n\n\n", "\n^2Available Super Spectate ^3options:\n", player, _aspeco, 1);
-                               return true;
-                       }
-
-                       if(argv(1) == "clear")
-                       {
-                               player.superspec_flags = 0;
-                               _start = 2;
-                       }
-
-                       for(i = _start; i < cmd_argc; ++i)
-                       {
-                               if(argv(i) == "on" || argv(i) == "1")
-                               {
-                                       player.superspec_flags |= _bits;
-                                       _bits = 0;
-                               }
-                               else if(argv(i) == "off" || argv(i) == "0")
-                               {
-                                       if(_start == 1)
-                                               player.superspec_flags &= ~_bits;
-
-                                       _bits = 0;
-                               }
-                               else
-                               {
-                                       if((argv(i) == "silent") || (argv(i) == "si")) _bits |= SSF_SILENT ;
-                                       if((argv(i) == "verbose") || (argv(i) == "ve")) _bits |= SSF_VERBOSE;
-                                       if((argv(i) == "item_message") || (argv(i) == "im")) _bits |= SSF_ITEMMSG;
-                               }
-                       }
-               }
-
-               _aspeco = "";
-               OPTIONINFO(player.superspec_flags, _aspeco, SSF_SILENT, "Silent", "silent", "si");
-               OPTIONINFO(player.superspec_flags, _aspeco, SSF_VERBOSE, "Verbose", "verbose", "ve");
-               OPTIONINFO(player.superspec_flags, _aspeco, SSF_ITEMMSG, "Item pickup messages", "item_message", "im");
-
-               superspec_msg("^3Current Super Spectate options are:\n\n\n\n\n", "\n^3Current Super Spectate options are:\n", player, _aspeco, 1);
-
-               return true;
-       }
-
-/////////////////////
-
-       if(cmd_name == "autospec")
-       {
-               string _aspeco;
-               if(cmd_argc > 1)
-               {
-                       if(argv(1) == "help")
-                       {
-                               _aspeco = "use cmd autospec [option] [on|off] to set options\n\n";
-                               _aspeco = strcat(_aspeco, "^3 strength ^7(short^5 st^7) for automatic spectate on strength powerup\n");
-                               _aspeco = strcat(_aspeco, "^3 shield ^7(short^5 sh^7) for automatic spectate on shield powerup\n");
-                               _aspeco = strcat(_aspeco, "^3 mega_health ^7(short^5 mh^7) for automatic spectate on mega health\n");
-                               _aspeco = strcat(_aspeco, "^3 mega_armor ^7(short^5 ma^7) for automatic spectate on mega armor\n");
-                               _aspeco = strcat(_aspeco, "^3 flag_grab ^7(short^5 fg^7) for automatic spectate on CTF flag grab\n");
-                               _aspeco = strcat(_aspeco, "^3 observer_only ^7(short^5 oo^7) for automatic spectate only if in observer mode\n");
-                               _aspeco = strcat(_aspeco, "^3 show_what ^7(short^5 sw^7) to display what event triggered autospectate\n");
-                               _aspeco = strcat(_aspeco, "^3 item_msg ^7(short^5 im^7) to autospec when item_message in superspectate is triggered\n");
-                               _aspeco = strcat(_aspeco, "^3 followkiller ^7(short ^5fk^7) to autospec the killer/off\n");
-                               _aspeco = strcat(_aspeco, "^3 all ^7(short ^5aa^7) to turn everything on/off\n");
-                               superspec_msg("^2Available Auto Spectate ^3options:\n\n\n", "\n^2Available Auto Spectate ^3options:\n", player, _aspeco, 1);
-                               return true;
-                       }
-
-                       float i, _bits = 0, _start = 1;
-                       if(argv(1) == "clear")
-                       {
-                               player.autospec_flags = 0;
-                               _start = 2;
-                       }
-
-                       for(i = _start; i < cmd_argc; ++i)
-                       {
-                               if(argv(i) == "on" || argv(i) == "1")
-                               {
-                                       player.autospec_flags |= _bits;
-                                       _bits = 0;
-                               }
-                               else if(argv(i) == "off" || argv(i) == "0")
-                               {
-                                       if(_start == 1)
-                                               player.autospec_flags &= ~_bits;
-
-                                       _bits = 0;
-                               }
-                               else
-                               {
-                                       if((argv(i) == "strength") || (argv(i) == "st")) _bits |= ASF_STRENGTH;
-                                       if((argv(i) == "shield") || (argv(i) == "sh")) _bits |= ASF_SHIELD;
-                                       if((argv(i) == "mega_health") || (argv(i) == "mh")) _bits |= ASF_MEGA_HP;
-                                       if((argv(i) == "mega_armor") || (argv(i) == "ma")) _bits |= ASF_MEGA_AR;
-                                       if((argv(i) == "flag_grab") || (argv(i) == "fg")) _bits |= ASF_FLAG_GRAB;
-                                       if((argv(i) == "observer_only") || (argv(i) == "oo")) _bits |= ASF_OBSERVER_ONLY;
-                                       if((argv(i) == "show_what") || (argv(i) == "sw")) _bits |= ASF_SHOWWHAT;
-                                       if((argv(i) == "item_msg") || (argv(i) == "im")) _bits |= ASF_SSIM;
-                                       if((argv(i) == "followkiller") || (argv(i) == "fk")) _bits |= ASF_FOLLOWKILLER;
-                                       if((argv(i) == "all") || (argv(i) == "aa")) _bits |= ASF_ALL;
-                               }
-                       }
-               }
-
-               _aspeco = "";
-               OPTIONINFO(player.autospec_flags, _aspeco, ASF_STRENGTH, "Strength", "strength", "st");
-               OPTIONINFO(player.autospec_flags, _aspeco, ASF_SHIELD, "Shield", "shield", "sh");
-               OPTIONINFO(player.autospec_flags, _aspeco, ASF_MEGA_HP, "Mega Health", "mega_health", "mh");
-               OPTIONINFO(player.autospec_flags, _aspeco, ASF_MEGA_AR, "Mega Armor", "mega_armor", "ma");
-               OPTIONINFO(player.autospec_flags, _aspeco, ASF_FLAG_GRAB, "Flag grab", "flag_grab","fg");
-               OPTIONINFO(player.autospec_flags, _aspeco, ASF_OBSERVER_ONLY, "Only switch if observer", "observer_only", "oo");
-               OPTIONINFO(player.autospec_flags, _aspeco, ASF_SHOWWHAT, "Show what item triggered spectate", "show_what", "sw");
-               OPTIONINFO(player.autospec_flags, _aspeco, ASF_SSIM, "Switch on superspec item message", "item_msg", "im");
-               OPTIONINFO(player.autospec_flags, _aspeco, ASF_FOLLOWKILLER, "Followkiller", "followkiller", "fk");
-
-               superspec_msg("^3Current auto spectate options are:\n\n\n\n\n", "\n^3Current auto spectate options are:\n", player, _aspeco, 1);
-               return true;
-       }
-
-       if(cmd_name == "followpowerup")
-       {
-               FOREACH_CLIENT(IS_PLAYER(it) && (it.strength_finished > time || it.invincible_finished > time), LAMBDA(return superspec_Spectate(player, it)));
-
-               superspec_msg("", "", player, "No active powerup\n", 1);
-               return true;
-       }
-
-       if(cmd_name == "followstrength")
-       {
-               FOREACH_CLIENT(IS_PLAYER(it) && it.strength_finished > time, LAMBDA(return superspec_Spectate(player, it)));
-
-               superspec_msg("", "", player, "No active Strength\n", 1);
-               return true;
-       }
-
-       if(cmd_name == "followshield")
-       {
-               FOREACH_CLIENT(IS_PLAYER(it) && it.invincible_finished > time, LAMBDA(return superspec_Spectate(player, it)));
-
-               superspec_msg("", "", player, "No active Shield\n", 1);
-               return true;
-       }
-#undef OPTIONINFO
-}
-
-MUTATOR_HOOKFUNCTION(superspec, BuildMutatorsString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":SS");
-}
-
-MUTATOR_HOOKFUNCTION(superspec, BuildMutatorsPrettyString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Super Spectators");
-}
-
-void superspec_hello(entity this)
-{
-       if(this.enemy.crypto_idfp == "")
-               Send_Notification(NOTIF_ONE_ONLY, this.enemy, MSG_INFO, INFO_SUPERSPEC_MISSING_UID);
-
-       delete(this);
-}
-
-MUTATOR_HOOKFUNCTION(superspec, ClientConnect)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(!IS_REAL_CLIENT(player))
-               return;
-
-       string fn = "superspec-local.options";
-       float fh;
-
-       player.superspec_flags = SSF_VERBOSE;
-       player.superspec_itemfilter = "";
-
-       entity _hello = spawn();
-       _hello.enemy = player;
-       setthink(_hello, superspec_hello);
-       _hello.nextthink = time + 5;
-
-       if (!_ISLOCAL(player))
-       {
-               if(player.crypto_idfp == "")
-                       return;
-
-               fn = sprintf("superspec-%s.options", uri_escape(player.crypto_idfp));
-       }
-
-       fh = fopen(fn, FILE_READ);
-       if(fh < 0)
-       {
-               LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for reading.");
-       }
-       else
-       {
-               string _magic = fgets(fh);
-               if(_magic != _SSMAGIX)
-               {
-                       LOG_TRACE("^1ERROR^7 While reading superspec options file: unknown magic");
-               }
-               else
-               {
-                       player.autospec_flags = stof(fgets(fh));
-                       player.superspec_flags = stof(fgets(fh));
-                       player.superspec_itemfilter = strzone(fgets(fh));
-               }
-               fclose(fh);
-       }
-}
-
-MUTATOR_HOOKFUNCTION(superspec, PlayerDies)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-
-       FOREACH_CLIENT(IS_SPEC(it), LAMBDA(
-               if(it.autospec_flags & ASF_FOLLOWKILLER && IS_PLAYER(frag_attacker) && it.enemy == frag_target)
-               {
-                       if(it.autospec_flags & ASF_SHOWWHAT)
-                               superspec_msg("", "", it, sprintf("^7Following %s^7 due to followkiller\n", frag_attacker.netname), 2);
-
-                       superspec_Spectate(it, frag_attacker);
-               }
-       ));
-}
-
-MUTATOR_HOOKFUNCTION(superspec, ClientDisconnect)
-{
-       entity player = M_ARGV(0, entity);
-
-       superspec_save_client_conf(player);
-}
-#endif
diff --git a/qcsrc/common/mutators/mutator/superspec/sv_superspec.qc b/qcsrc/common/mutators/mutator/superspec/sv_superspec.qc
new file mode 100644 (file)
index 0000000..c423042
--- /dev/null
@@ -0,0 +1,459 @@
+#include "sv_superspec.qh"
+
+REGISTER_MUTATOR(superspec, cvar("g_superspectate"));
+
+#define _SSMAGIX "SUPERSPEC_OPTIONSFILE_V1"
+#define _ISLOCAL(ent) ((edict_num(1) == (ent)) ? true : false)
+
+const float ASF_STRENGTH               = BIT(0);
+const float ASF_SHIELD                         = BIT(1);
+const float ASF_MEGA_AR                = BIT(2);
+const float ASF_MEGA_HP                = BIT(3);
+const float ASF_FLAG_GRAB              = BIT(4);
+const float ASF_OBSERVER_ONLY  = BIT(5);
+const float ASF_SHOWWHAT               = BIT(6);
+const float ASF_SSIM                   = BIT(7);
+const float ASF_FOLLOWKILLER   = BIT(8);
+const float ASF_ALL                    = 0xFFFFFF;
+.float autospec_flags;
+
+const float SSF_SILENT = 1;
+const float SSF_VERBOSE = 2;
+const float SSF_ITEMMSG = 4;
+.float superspec_flags;
+
+.string superspec_itemfilter; //"classname1 classname2 ..."
+
+bool superspec_Spectate(entity this, entity targ)
+{
+       if(Spectate(this, targ) == 1)
+           TRANSMUTE(Spectator, this);
+
+       return true;
+}
+
+void superspec_save_client_conf(entity this)
+{
+       string fn = "superspec-local.options";
+       float fh;
+
+       if (!_ISLOCAL(this))
+       {
+               if(this.crypto_idfp == "")
+                       return;
+
+               fn = sprintf("superspec-%s.options", uri_escape(this.crypto_idfp));
+       }
+
+       fh = fopen(fn, FILE_WRITE);
+       if(fh < 0)
+       {
+               LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for writing.");
+       }
+       else
+       {
+               fputs(fh, _SSMAGIX);
+               fputs(fh, "\n");
+               fputs(fh, ftos(this.autospec_flags));
+               fputs(fh, "\n");
+               fputs(fh, ftos(this.superspec_flags));
+               fputs(fh, "\n");
+               fputs(fh, this.superspec_itemfilter);
+               fputs(fh, "\n");
+               fclose(fh);
+       }
+}
+
+void superspec_msg(string _center_title, string _con_title, entity _to, string _msg, float _spamlevel)
+{
+       sprint(_to, strcat(_con_title, _msg));
+
+       if(_to.superspec_flags & SSF_SILENT)
+               return;
+
+       if(_spamlevel > 1)
+               if (!(_to.superspec_flags & SSF_VERBOSE))
+                       return;
+
+       centerprint(_to, strcat(_center_title, _msg));
+}
+
+float superspec_filteritem(entity _for, entity _item)
+{
+       float i;
+
+       if(_for.superspec_itemfilter == "")
+               return true;
+
+       if(_for.superspec_itemfilter == "")
+               return true;
+
+       float l = tokenize_console(_for.superspec_itemfilter);
+       for(i = 0; i < l; ++i)
+       {
+               if(argv(i) == _item.classname)
+                       return true;
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(superspec, ItemTouch)
+{
+       entity item = M_ARGV(0, entity);
+       entity toucher = M_ARGV(1, entity);
+
+       FOREACH_CLIENT(true, LAMBDA(
+               if(!IS_SPEC(it) && !IS_OBSERVER(it))
+                       continue;
+               if(it.superspec_flags & SSF_ITEMMSG)
+                       if(superspec_filteritem(it, item))
+                       {
+                               if(it.superspec_flags & SSF_VERBOSE)
+                                       superspec_msg("", "", it, sprintf("Player %s^7 just picked up ^3%s\n", toucher.netname, item.netname), 1);
+                               else
+                                       superspec_msg("", "", it, sprintf("Player %s^7 just picked up ^3%s\n^8(%s^8)\n", toucher.netname, item.netname, item.classname), 1);
+                               if((it.autospec_flags & ASF_SSIM) && it.enemy != toucher)
+                               {
+                                       superspec_Spectate(it, toucher);
+                                       return MUT_ITEMTOUCH_CONTINUE;
+                               }
+                       }
+
+               if((it.autospec_flags & ASF_SHIELD && item.invincible_finished) ||
+                       (it.autospec_flags & ASF_STRENGTH && item.strength_finished) ||
+                       (it.autospec_flags & ASF_MEGA_AR && item.itemdef == ITEM_ArmorMega) ||
+                       (it.autospec_flags & ASF_MEGA_HP && item.itemdef == ITEM_HealthMega) ||
+                       (it.autospec_flags & ASF_FLAG_GRAB && item.classname == "item_flag_team"))
+               {
+
+                       if((it.enemy != toucher) || IS_OBSERVER(it))
+                       {
+                               if(it.autospec_flags & ASF_OBSERVER_ONLY && !IS_OBSERVER(it))
+                               {
+                                       if(it.superspec_flags & SSF_VERBOSE)
+                                               superspec_msg("", "", it, sprintf("^8Ignored that ^7%s^8 grabbed %s^8 since the observer_only option is ON\n", toucher.netname, item.netname), 2);
+                               }
+                               else
+                               {
+                                       if(it.autospec_flags & ASF_SHOWWHAT)
+                                               superspec_msg("", "", it, sprintf("^7Following %s^7 due to picking up %s\n", toucher.netname, item.netname), 2);
+
+                                       superspec_Spectate(it, toucher);
+                               }
+                       }
+               }
+       ));
+
+       return MUT_ITEMTOUCH_CONTINUE;
+}
+
+MUTATOR_HOOKFUNCTION(superspec, SV_ParseClientCommand)
+{
+#define OPTIONINFO(flag,var,test,text,long,short) \
+    var = strcat(var, ((flag & test) ? "^2[ON]  ^7" : "^1[OFF] ^7")); \
+    var = strcat(var, text," ^7(^3 ", long, "^7 | ^3", short, " ^7)\n")
+
+       if(MUTATOR_RETURNVALUE) // command was already handled?
+               return;
+
+       entity player = M_ARGV(0, entity);
+       string cmd_name = M_ARGV(1, string);
+       int cmd_argc = M_ARGV(2, int);
+
+       if(IS_PLAYER(player))
+               return;
+
+       if(cmd_name == "superspec_itemfilter")
+       {
+               if(argv(1) == "help")
+               {
+                       string _aspeco;
+                       _aspeco = "^7 superspec_itemfilter ^3\"item_classname1 item_classname2\"^7 only show thise items when ^2superspec ^3item_message^7 is on\n";
+                       _aspeco = strcat(_aspeco, "^3 clear^7 Remove the filter (show all pickups)\n");
+                       _aspeco = strcat(_aspeco, "^3 show ^7 Display current filter\n");
+                       superspec_msg("^3superspec_itemfilter help:\n\n\n", "\n^3superspec_itemfilter help:\n", player, _aspeco, 1);
+               }
+               else if(argv(1) == "clear")
+               {
+                       if(player.superspec_itemfilter != "")
+                               strunzone(player.superspec_itemfilter);
+
+                       player.superspec_itemfilter = "";
+               }
+               else if(argv(1) == "show" || argv(1) == "")
+               {
+                       if(player.superspec_itemfilter == "")
+                       {
+                               superspec_msg("^3superspec_itemfilter^7 is ^1not^7 set", "\n^3superspec_itemfilter^7 is ^1not^7 set\n", player, "", 1);
+                               return true;
+                       }
+                       float i;
+                       float l = tokenize_console(player.superspec_itemfilter);
+                       string _msg = "";
+                       for(i = 0; i < l; ++i)
+                               _msg = strcat(_msg, "^3#", ftos(i), " ^7", argv(i), "\n");
+                               //_msg = sprintf("^3#%d^7 %s\n%s", i, _msg, argv(i));
+
+                       _msg = strcat(_msg,"\n");
+
+                       superspec_msg("^3superspec_itemfilter is:\n\n\n", "\n^3superspec_itemfilter is:\n", player, _msg, 1);
+               }
+               else
+               {
+                       if(player.superspec_itemfilter != "")
+                               strunzone(player.superspec_itemfilter);
+
+                       player.superspec_itemfilter = strzone(argv(1));
+               }
+
+               return true;
+       }
+
+       if(cmd_name == "superspec")
+       {
+               string _aspeco;
+
+               if(cmd_argc > 1)
+               {
+                       float i, _bits = 0, _start = 1;
+                       if(argv(1) == "help")
+                       {
+                               _aspeco = "use cmd superspec [option] [on|off] to set options\n\n";
+                               _aspeco = strcat(_aspeco, "^3 silent ^7(short^5 si^7) supresses ALL messages from superspectate.\n");
+                               _aspeco = strcat(_aspeco, "^3 verbose ^7(short^5 ve^7) makes superspectate print some additional information.\n");
+                               _aspeco = strcat(_aspeco, "^3 item_message ^7(short^5 im^7) makes superspectate print items that were picked up.\n");
+                               _aspeco = strcat(_aspeco, "^7    Use cmd superspec_itemfilter \"item_class1 item_class2\" to set up a filter of what to show with ^3item_message.\n");
+                               superspec_msg("^2Available Super Spectate ^3options:\n\n\n", "\n^2Available Super Spectate ^3options:\n", player, _aspeco, 1);
+                               return true;
+                       }
+
+                       if(argv(1) == "clear")
+                       {
+                               player.superspec_flags = 0;
+                               _start = 2;
+                       }
+
+                       for(i = _start; i < cmd_argc; ++i)
+                       {
+                               if(argv(i) == "on" || argv(i) == "1")
+                               {
+                                       player.superspec_flags |= _bits;
+                                       _bits = 0;
+                               }
+                               else if(argv(i) == "off" || argv(i) == "0")
+                               {
+                                       if(_start == 1)
+                                               player.superspec_flags &= ~_bits;
+
+                                       _bits = 0;
+                               }
+                               else
+                               {
+                                       if((argv(i) == "silent") || (argv(i) == "si")) _bits |= SSF_SILENT ;
+                                       if((argv(i) == "verbose") || (argv(i) == "ve")) _bits |= SSF_VERBOSE;
+                                       if((argv(i) == "item_message") || (argv(i) == "im")) _bits |= SSF_ITEMMSG;
+                               }
+                       }
+               }
+
+               _aspeco = "";
+               OPTIONINFO(player.superspec_flags, _aspeco, SSF_SILENT, "Silent", "silent", "si");
+               OPTIONINFO(player.superspec_flags, _aspeco, SSF_VERBOSE, "Verbose", "verbose", "ve");
+               OPTIONINFO(player.superspec_flags, _aspeco, SSF_ITEMMSG, "Item pickup messages", "item_message", "im");
+
+               superspec_msg("^3Current Super Spectate options are:\n\n\n\n\n", "\n^3Current Super Spectate options are:\n", player, _aspeco, 1);
+
+               return true;
+       }
+
+/////////////////////
+
+       if(cmd_name == "autospec")
+       {
+               string _aspeco;
+               if(cmd_argc > 1)
+               {
+                       if(argv(1) == "help")
+                       {
+                               _aspeco = "use cmd autospec [option] [on|off] to set options\n\n";
+                               _aspeco = strcat(_aspeco, "^3 strength ^7(short^5 st^7) for automatic spectate on strength powerup\n");
+                               _aspeco = strcat(_aspeco, "^3 shield ^7(short^5 sh^7) for automatic spectate on shield powerup\n");
+                               _aspeco = strcat(_aspeco, "^3 mega_health ^7(short^5 mh^7) for automatic spectate on mega health\n");
+                               _aspeco = strcat(_aspeco, "^3 mega_armor ^7(short^5 ma^7) for automatic spectate on mega armor\n");
+                               _aspeco = strcat(_aspeco, "^3 flag_grab ^7(short^5 fg^7) for automatic spectate on CTF flag grab\n");
+                               _aspeco = strcat(_aspeco, "^3 observer_only ^7(short^5 oo^7) for automatic spectate only if in observer mode\n");
+                               _aspeco = strcat(_aspeco, "^3 show_what ^7(short^5 sw^7) to display what event triggered autospectate\n");
+                               _aspeco = strcat(_aspeco, "^3 item_msg ^7(short^5 im^7) to autospec when item_message in superspectate is triggered\n");
+                               _aspeco = strcat(_aspeco, "^3 followkiller ^7(short ^5fk^7) to autospec the killer/off\n");
+                               _aspeco = strcat(_aspeco, "^3 all ^7(short ^5aa^7) to turn everything on/off\n");
+                               superspec_msg("^2Available Auto Spectate ^3options:\n\n\n", "\n^2Available Auto Spectate ^3options:\n", player, _aspeco, 1);
+                               return true;
+                       }
+
+                       float i, _bits = 0, _start = 1;
+                       if(argv(1) == "clear")
+                       {
+                               player.autospec_flags = 0;
+                               _start = 2;
+                       }
+
+                       for(i = _start; i < cmd_argc; ++i)
+                       {
+                               if(argv(i) == "on" || argv(i) == "1")
+                               {
+                                       player.autospec_flags |= _bits;
+                                       _bits = 0;
+                               }
+                               else if(argv(i) == "off" || argv(i) == "0")
+                               {
+                                       if(_start == 1)
+                                               player.autospec_flags &= ~_bits;
+
+                                       _bits = 0;
+                               }
+                               else
+                               {
+                                       if((argv(i) == "strength") || (argv(i) == "st")) _bits |= ASF_STRENGTH;
+                                       if((argv(i) == "shield") || (argv(i) == "sh")) _bits |= ASF_SHIELD;
+                                       if((argv(i) == "mega_health") || (argv(i) == "mh")) _bits |= ASF_MEGA_HP;
+                                       if((argv(i) == "mega_armor") || (argv(i) == "ma")) _bits |= ASF_MEGA_AR;
+                                       if((argv(i) == "flag_grab") || (argv(i) == "fg")) _bits |= ASF_FLAG_GRAB;
+                                       if((argv(i) == "observer_only") || (argv(i) == "oo")) _bits |= ASF_OBSERVER_ONLY;
+                                       if((argv(i) == "show_what") || (argv(i) == "sw")) _bits |= ASF_SHOWWHAT;
+                                       if((argv(i) == "item_msg") || (argv(i) == "im")) _bits |= ASF_SSIM;
+                                       if((argv(i) == "followkiller") || (argv(i) == "fk")) _bits |= ASF_FOLLOWKILLER;
+                                       if((argv(i) == "all") || (argv(i) == "aa")) _bits |= ASF_ALL;
+                               }
+                       }
+               }
+
+               _aspeco = "";
+               OPTIONINFO(player.autospec_flags, _aspeco, ASF_STRENGTH, "Strength", "strength", "st");
+               OPTIONINFO(player.autospec_flags, _aspeco, ASF_SHIELD, "Shield", "shield", "sh");
+               OPTIONINFO(player.autospec_flags, _aspeco, ASF_MEGA_HP, "Mega Health", "mega_health", "mh");
+               OPTIONINFO(player.autospec_flags, _aspeco, ASF_MEGA_AR, "Mega Armor", "mega_armor", "ma");
+               OPTIONINFO(player.autospec_flags, _aspeco, ASF_FLAG_GRAB, "Flag grab", "flag_grab","fg");
+               OPTIONINFO(player.autospec_flags, _aspeco, ASF_OBSERVER_ONLY, "Only switch if observer", "observer_only", "oo");
+               OPTIONINFO(player.autospec_flags, _aspeco, ASF_SHOWWHAT, "Show what item triggered spectate", "show_what", "sw");
+               OPTIONINFO(player.autospec_flags, _aspeco, ASF_SSIM, "Switch on superspec item message", "item_msg", "im");
+               OPTIONINFO(player.autospec_flags, _aspeco, ASF_FOLLOWKILLER, "Followkiller", "followkiller", "fk");
+
+               superspec_msg("^3Current auto spectate options are:\n\n\n\n\n", "\n^3Current auto spectate options are:\n", player, _aspeco, 1);
+               return true;
+       }
+
+       if(cmd_name == "followpowerup")
+       {
+               FOREACH_CLIENT(IS_PLAYER(it) && (it.strength_finished > time || it.invincible_finished > time), LAMBDA(return superspec_Spectate(player, it)));
+
+               superspec_msg("", "", player, "No active powerup\n", 1);
+               return true;
+       }
+
+       if(cmd_name == "followstrength")
+       {
+               FOREACH_CLIENT(IS_PLAYER(it) && it.strength_finished > time, LAMBDA(return superspec_Spectate(player, it)));
+
+               superspec_msg("", "", player, "No active Strength\n", 1);
+               return true;
+       }
+
+       if(cmd_name == "followshield")
+       {
+               FOREACH_CLIENT(IS_PLAYER(it) && it.invincible_finished > time, LAMBDA(return superspec_Spectate(player, it)));
+
+               superspec_msg("", "", player, "No active Shield\n", 1);
+               return true;
+       }
+#undef OPTIONINFO
+}
+
+MUTATOR_HOOKFUNCTION(superspec, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":SS");
+}
+
+MUTATOR_HOOKFUNCTION(superspec, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Super Spectators");
+}
+
+void superspec_hello(entity this)
+{
+       if(this.enemy.crypto_idfp == "")
+               Send_Notification(NOTIF_ONE_ONLY, this.enemy, MSG_INFO, INFO_SUPERSPEC_MISSING_UID);
+
+       delete(this);
+}
+
+MUTATOR_HOOKFUNCTION(superspec, ClientConnect)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(!IS_REAL_CLIENT(player))
+               return;
+
+       string fn = "superspec-local.options";
+       float fh;
+
+       player.superspec_flags = SSF_VERBOSE;
+       player.superspec_itemfilter = "";
+
+       entity _hello = spawn();
+       _hello.enemy = player;
+       setthink(_hello, superspec_hello);
+       _hello.nextthink = time + 5;
+
+       if (!_ISLOCAL(player))
+       {
+               if(player.crypto_idfp == "")
+                       return;
+
+               fn = sprintf("superspec-%s.options", uri_escape(player.crypto_idfp));
+       }
+
+       fh = fopen(fn, FILE_READ);
+       if(fh < 0)
+       {
+               LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for reading.");
+       }
+       else
+       {
+               string _magic = fgets(fh);
+               if(_magic != _SSMAGIX)
+               {
+                       LOG_TRACE("^1ERROR^7 While reading superspec options file: unknown magic");
+               }
+               else
+               {
+                       player.autospec_flags = stof(fgets(fh));
+                       player.superspec_flags = stof(fgets(fh));
+                       player.superspec_itemfilter = strzone(fgets(fh));
+               }
+               fclose(fh);
+       }
+}
+
+MUTATOR_HOOKFUNCTION(superspec, PlayerDies)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+
+       FOREACH_CLIENT(IS_SPEC(it), LAMBDA(
+               if(it.autospec_flags & ASF_FOLLOWKILLER && IS_PLAYER(frag_attacker) && it.enemy == frag_target)
+               {
+                       if(it.autospec_flags & ASF_SHOWWHAT)
+                               superspec_msg("", "", it, sprintf("^7Following %s^7 due to followkiller\n", frag_attacker.netname), 2);
+
+                       superspec_Spectate(it, frag_attacker);
+               }
+       ));
+}
+
+MUTATOR_HOOKFUNCTION(superspec, ClientDisconnect)
+{
+       entity player = M_ARGV(0, entity);
+
+       superspec_save_client_conf(player);
+}
diff --git a/qcsrc/common/mutators/mutator/superspec/sv_superspec.qh b/qcsrc/common/mutators/mutator/superspec/sv_superspec.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 42dad3926e539193afb390660b551c6b70e97237..f341e2afe1993bd1bc0d0d179eb770dea76d7652 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/touchexplode/touchexplode.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/touchexplode/sv_touchexplode.qc>
+#endif
index ec71f52d749c7d6cc799ae3c6a03e9f21bc0e1e9..18cdcc60f698a187a2e434a2c8e142fdf6a258dc 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/touchexplode/touchexplode.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/touchexplode/sv_touchexplode.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/touchexplode/module.inc b/qcsrc/common/mutators/mutator/touchexplode/module.inc
deleted file mode 100644 (file)
index d3b0ea5..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "touchexplode.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/touchexplode/sv_touchexplode.qc b/qcsrc/common/mutators/mutator/touchexplode/sv_touchexplode.qc
new file mode 100644 (file)
index 0000000..38ac305
--- /dev/null
@@ -0,0 +1,47 @@
+#include "sv_touchexplode.qh"
+
+float autocvar_g_touchexplode_radius;
+float autocvar_g_touchexplode_damage;
+float autocvar_g_touchexplode_edgedamage;
+float autocvar_g_touchexplode_force;
+
+REGISTER_MUTATOR(touchexplode, cvar("g_touchexplode"));
+
+.float touchexplode_time;
+
+void PlayerTouchExplode(entity p1, entity p2)
+{
+       vector org = (p1.origin + p2.origin) * 0.5;
+       org.z += (p1.mins.z + p2.mins.z) * 0.5;
+
+       sound(p1, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
+       Send_Effect(EFFECT_EXPLOSION_SMALL, org, '0 0 0', 1);
+
+       entity e = spawn();
+       setorigin(e, org);
+       RadiusDamage(e, NULL, autocvar_g_touchexplode_damage, autocvar_g_touchexplode_edgedamage, autocvar_g_touchexplode_radius, NULL, NULL, autocvar_g_touchexplode_force, DEATH_TOUCHEXPLODE.m_id, NULL);
+       delete(e);
+}
+
+MUTATOR_HOOKFUNCTION(touchexplode, PlayerPreThink)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(time > player.touchexplode_time)
+       if(!gameover)
+       if(!STAT(FROZEN, player))
+       if(IS_PLAYER(player))
+       if(!IS_DEAD(player))
+       if(!IS_INDEPENDENT_PLAYER(player))
+               FOREACH_CLIENT(IS_PLAYER(it) && it != player, LAMBDA(
+                       if(time > it.touchexplode_time)
+                       if(!STAT(FROZEN, it))
+                       if(!IS_DEAD(it))
+                       if (!IS_INDEPENDENT_PLAYER(it))
+                       if(boxesoverlap(player.absmin, player.absmax, it.absmin, it.absmax))
+                       {
+                               PlayerTouchExplode(player, it);
+                               player.touchexplode_time = it.touchexplode_time = time + 0.2;
+                       }
+               ));
+}
diff --git a/qcsrc/common/mutators/mutator/touchexplode/sv_touchexplode.qh b/qcsrc/common/mutators/mutator/touchexplode/sv_touchexplode.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mutators/mutator/touchexplode/touchexplode.qc b/qcsrc/common/mutators/mutator/touchexplode/touchexplode.qc
deleted file mode 100644 (file)
index c585e7e..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifdef IMPLEMENTATION
-float autocvar_g_touchexplode_radius;
-float autocvar_g_touchexplode_damage;
-float autocvar_g_touchexplode_edgedamage;
-float autocvar_g_touchexplode_force;
-
-REGISTER_MUTATOR(touchexplode, cvar("g_touchexplode"));
-
-.float touchexplode_time;
-
-void PlayerTouchExplode(entity p1, entity p2)
-{
-       vector org = (p1.origin + p2.origin) * 0.5;
-       org.z += (p1.mins.z + p2.mins.z) * 0.5;
-
-       sound(p1, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
-       Send_Effect(EFFECT_EXPLOSION_SMALL, org, '0 0 0', 1);
-
-       entity e = spawn();
-       setorigin(e, org);
-       RadiusDamage(e, NULL, autocvar_g_touchexplode_damage, autocvar_g_touchexplode_edgedamage, autocvar_g_touchexplode_radius, NULL, NULL, autocvar_g_touchexplode_force, DEATH_TOUCHEXPLODE.m_id, NULL);
-       delete(e);
-}
-
-MUTATOR_HOOKFUNCTION(touchexplode, PlayerPreThink)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(time > player.touchexplode_time)
-       if(!gameover)
-       if(!STAT(FROZEN, player))
-       if(IS_PLAYER(player))
-       if(!IS_DEAD(player))
-       if(!IS_INDEPENDENT_PLAYER(player))
-               FOREACH_CLIENT(IS_PLAYER(it) && it != player, LAMBDA(
-                       if(time > it.touchexplode_time)
-                       if(!STAT(FROZEN, it))
-                       if(!IS_DEAD(it))
-                       if (!IS_INDEPENDENT_PLAYER(it))
-                       if(boxesoverlap(player.absmin, player.absmax, it.absmin, it.absmax))
-                       {
-                               PlayerTouchExplode(player, it);
-                               player.touchexplode_time = it.touchexplode_time = time + 0.2;
-                       }
-               ));
-}
-#endif
index 856ed84c463aa54dbb0fc71943fcfc4b4d8af34f..57b844451a552879e996ce53673ab242122d2e15 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/vampire/vampire.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/vampire/sv_vampire.qc>
+#endif
index 551184c77bb422d812af35d50d3dcd2e634144d8..d7d8a4143c5cd9b7b7a73308086164734760dc6c 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/vampire/vampire.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/vampire/sv_vampire.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/vampire/module.inc b/qcsrc/common/mutators/mutator/vampire/module.inc
deleted file mode 100644 (file)
index 864ea28..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "vampire.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/vampire/sv_vampire.qc b/qcsrc/common/mutators/mutator/vampire/sv_vampire.qc
new file mode 100644 (file)
index 0000000..3a435c5
--- /dev/null
@@ -0,0 +1,28 @@
+#include "sv_vampire.qh"
+
+REGISTER_MUTATOR(vampire, cvar("g_vampire") && !cvar("g_instagib"));
+
+MUTATOR_HOOKFUNCTION(vampire, PlayerDamage_SplitHealthArmor)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       float damage_take = M_ARGV(4, float);
+
+       if(time >= frag_target.spawnshieldtime)
+       if(frag_target != frag_attacker)
+       if(!IS_DEAD(frag_target))
+       {
+               frag_attacker.health += bound(0, damage_take, frag_target.health);
+               frag_attacker.health = bound(0, frag_attacker.health, autocvar_g_balance_health_limit);
+       }
+}
+
+MUTATOR_HOOKFUNCTION(vampire, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":Vampire");
+}
+
+MUTATOR_HOOKFUNCTION(vampire, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Vampire");
+}
diff --git a/qcsrc/common/mutators/mutator/vampire/sv_vampire.qh b/qcsrc/common/mutators/mutator/vampire/sv_vampire.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mutators/mutator/vampire/vampire.qc b/qcsrc/common/mutators/mutator/vampire/vampire.qc
deleted file mode 100644 (file)
index d245c80..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(vampire, cvar("g_vampire") && !cvar("g_instagib"));
-
-MUTATOR_HOOKFUNCTION(vampire, PlayerDamage_SplitHealthArmor)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-       float damage_take = M_ARGV(4, float);
-
-       if(time >= frag_target.spawnshieldtime)
-       if(frag_target != frag_attacker)
-       if(!IS_DEAD(frag_target))
-       {
-               frag_attacker.health += bound(0, damage_take, frag_target.health);
-               frag_attacker.health = bound(0, frag_attacker.health, autocvar_g_balance_health_limit);
-       }
-}
-
-MUTATOR_HOOKFUNCTION(vampire, BuildMutatorsString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":Vampire");
-}
-
-MUTATOR_HOOKFUNCTION(vampire, BuildMutatorsPrettyString)
-{
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Vampire");
-}
-#endif
index 868a4ef3fc2e6688214aec9c10c2fab117dc1868..72b2bacb9c1796aa5addc651711c4dec14dcab26 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/vampirehook/vampirehook.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/vampirehook/sv_vampirehook.qc>
+#endif
index 5d57816c9634743c906ba032f5f78e1d0fc0106e..eaa7b320a8f5ccb9eb494fd54a9d6434ca434929 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/vampirehook/vampirehook.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/vampirehook/sv_vampirehook.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/vampirehook/module.inc b/qcsrc/common/mutators/mutator/vampirehook/module.inc
deleted file mode 100644 (file)
index 17ecf60..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "vampirehook.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/vampirehook/sv_vampirehook.qc b/qcsrc/common/mutators/mutator/vampirehook/sv_vampirehook.qc
new file mode 100644 (file)
index 0000000..e2b0f57
--- /dev/null
@@ -0,0 +1,37 @@
+#include "sv_vampirehook.qh"
+
+REGISTER_MUTATOR(vh, cvar("g_vampirehook"));
+
+bool autocvar_g_vampirehook_teamheal;
+float autocvar_g_vampirehook_damage;
+float autocvar_g_vampirehook_damagerate;
+float autocvar_g_vampirehook_health_steal;
+
+.float last_dmg;
+
+MUTATOR_HOOKFUNCTION(vh, GrappleHookThink)
+{
+       entity thehook = M_ARGV(0, entity);
+
+       entity dmgent = ((SAME_TEAM(thehook.owner, thehook.aiment) && autocvar_g_vampirehook_teamheal) ? thehook.owner : thehook.aiment);
+
+       if(IS_PLAYER(thehook.aiment))
+       if(thehook.last_dmg < time)
+       if(!STAT(FROZEN, thehook.aiment))
+       if(time >= game_starttime)
+       if(DIFF_TEAM(thehook.owner, thehook.aiment) || autocvar_g_vampirehook_teamheal)
+       if(thehook.aiment.health > 0)
+       if(autocvar_g_vampirehook_damage)
+       {
+               thehook.last_dmg = time + autocvar_g_vampirehook_damagerate;
+               thehook.owner.damage_dealt += autocvar_g_vampirehook_damage;
+               Damage(dmgent, thehook, thehook.owner, autocvar_g_vampirehook_damage, WEP_HOOK.m_id, thehook.origin, '0 0 0');
+               if(SAME_TEAM(thehook.owner, thehook.aiment))
+                       thehook.aiment.health = min(thehook.aiment.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
+               else
+                       thehook.owner.health = min(thehook.owner.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
+
+               if(dmgent == thehook.owner)
+                       dmgent.health -= autocvar_g_vampirehook_damage; // FIXME: friendly fire?!
+       }
+}
diff --git a/qcsrc/common/mutators/mutator/vampirehook/sv_vampirehook.qh b/qcsrc/common/mutators/mutator/vampirehook/sv_vampirehook.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mutators/mutator/vampirehook/vampirehook.qc b/qcsrc/common/mutators/mutator/vampirehook/vampirehook.qc
deleted file mode 100644 (file)
index a54dc74..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(vh, cvar("g_vampirehook"));
-
-bool autocvar_g_vampirehook_teamheal;
-float autocvar_g_vampirehook_damage;
-float autocvar_g_vampirehook_damagerate;
-float autocvar_g_vampirehook_health_steal;
-
-.float last_dmg;
-
-MUTATOR_HOOKFUNCTION(vh, GrappleHookThink)
-{
-       entity thehook = M_ARGV(0, entity);
-
-       entity dmgent = ((SAME_TEAM(thehook.owner, thehook.aiment) && autocvar_g_vampirehook_teamheal) ? thehook.owner : thehook.aiment);
-
-       if(IS_PLAYER(thehook.aiment))
-       if(thehook.last_dmg < time)
-       if(!STAT(FROZEN, thehook.aiment))
-       if(time >= game_starttime)
-       if(DIFF_TEAM(thehook.owner, thehook.aiment) || autocvar_g_vampirehook_teamheal)
-       if(thehook.aiment.health > 0)
-       if(autocvar_g_vampirehook_damage)
-       {
-               thehook.last_dmg = time + autocvar_g_vampirehook_damagerate;
-               thehook.owner.damage_dealt += autocvar_g_vampirehook_damage;
-               Damage(dmgent, thehook, thehook.owner, autocvar_g_vampirehook_damage, WEP_HOOK.m_id, thehook.origin, '0 0 0');
-               if(SAME_TEAM(thehook.owner, thehook.aiment))
-                       thehook.aiment.health = min(thehook.aiment.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
-               else
-                       thehook.owner.health = min(thehook.owner.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
-
-               if(dmgent == thehook.owner)
-                       dmgent.health -= autocvar_g_vampirehook_damage; // FIXME: friendly fire?!
-       }
-}
-
-#endif
index 4645130551a3c1f4b6be52fb83771a790ee0de8f..77c4312001de399edeaaddd1d9a1abcc7de55020 100644 (file)
@@ -1,9 +1,8 @@
-#ifndef WAYPOINTS_ALL_H
-#define WAYPOINTS_ALL_H
+#pragma once
 
 #include "waypointsprites.qh"
 
-REGISTRY(Waypoints, BITS(6))
+REGISTRY(Waypoints, BITS(7))
 #define Waypoints_from(i) _Waypoints_from(i, WP_Null)
 REGISTER_REGISTRY(Waypoints)
 REGISTRY_CHECK(Waypoints)
@@ -58,5 +57,3 @@ REGISTER_RADARICON(Vehicle,         1);
 REGISTER_RADARICON(Weapon,          1);
 
 #include "all.inc"
-
-#endif
diff --git a/qcsrc/common/mutators/mutator/waypoints/module.inc b/qcsrc/common/mutators/mutator/waypoints/module.inc
deleted file mode 100644 (file)
index 50bb5b4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include "waypointsprites.qc"
index e99303823b9eb44e4efab3daf17fbb72692fba32..7e5f79317f6dc046238f83bf5c8995da2b12b077 100644 (file)
@@ -1,7 +1,5 @@
 #include "waypointsprites.qh"
 
-#ifdef IMPLEMENTATION
-
 REGISTER_MUTATOR(waypointsprites, true);
 
 REGISTER_NET_LINKED(waypointsprites)
@@ -18,10 +16,12 @@ bool WaypointSprite_SendEntity(entity this, entity to, float sendflags)
         sendflags |= 0x80;
 
     int f = 0;
-    if(this.currentammo)
+    if(this.currentammo == 1)
         f |= 1; // hideable
     if(this.exteriormodeltoclient == to)
         f |= 2; // my own
+    if(this.currentammo == 2)
+        f |= 2; // radar only
 
     MUTATOR_CALLHOOK(SendWaypoint, this, to, sendflags, f);
     sendflags = M_ARGV(2, int);
@@ -1147,4 +1147,3 @@ void WaypointSprite_PlayerGone(entity this)
     WaypointSprite_DetachCarrier(this);
 }
 #endif
-#endif
index 26e4058d24975ba686619ca785271826065e6a0d..6a420b734eacd1dcdf74dd37846cfc4d025cc48f 100644 (file)
@@ -1,5 +1,4 @@
-#ifndef WAYPOINTSPRITES_H
-#define WAYPOINTSPRITES_H
+#pragma once
 
 #include "all.qh"
 
@@ -118,6 +117,8 @@ void Draw_WaypointSprite(entity this);
 #endif
 
 #ifdef SVQC
+.entity sprite;
+
 float autocvar_sv_waypointsprite_deadlifetime;
 float autocvar_sv_waypointsprite_deployed_lifetime;
 float autocvar_sv_waypointsprite_limitedrange;
@@ -234,5 +235,3 @@ void WaypointSprite_PlayerDead(entity this);
 
 void WaypointSprite_PlayerGone(entity this);
 #endif
-
-#endif
index 742510b883501ca97946c1b851ed4ac6aa148b72..034b51d1177e3d3faab54e27b54c3ddffa75a7cc 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/weaponarena_random/weaponarena_random.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/weaponarena_random/sv_weaponarena_random.qc>
+#endif
index 68d6a24c4255ba1385aed7cd5f7c6e7d968f04f1..05b87c73d33471db8648db0d42a448bb7964d127 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <common/mutators/mutator/weaponarena_random/weaponarena_random.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/weaponarena_random/sv_weaponarena_random.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/weaponarena_random/module.inc b/qcsrc/common/mutators/mutator/weaponarena_random/module.inc
deleted file mode 100644 (file)
index b7a5f66..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef SVQC
-#include "weaponarena_random.qc"
-#endif
diff --git a/qcsrc/common/mutators/mutator/weaponarena_random/sv_weaponarena_random.qc b/qcsrc/common/mutators/mutator/weaponarena_random/sv_weaponarena_random.qc
new file mode 100644 (file)
index 0000000..7ac4504
--- /dev/null
@@ -0,0 +1,14 @@
+#include "sv_weaponarena_random.qh"
+
+// WEAPONTODO: rename the cvars
+REGISTER_MUTATOR(weaponarena_random, true);
+
+MUTATOR_HOOKFUNCTION(weaponarena_random, PlayerSpawn)
+{
+    if (!g_weaponarena_random) return;
+    entity player = M_ARGV(0, entity);
+
+    if (g_weaponarena_random_with_blaster) player.weapons &= ~WEPSET(BLASTER);
+    W_RandomWeapons(player, g_weaponarena_random);
+    if (g_weaponarena_random_with_blaster) player.weapons |= WEPSET(BLASTER);
+}
diff --git a/qcsrc/common/mutators/mutator/weaponarena_random/sv_weaponarena_random.qh b/qcsrc/common/mutators/mutator/weaponarena_random/sv_weaponarena_random.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mutators/mutator/weaponarena_random/weaponarena_random.qc b/qcsrc/common/mutators/mutator/weaponarena_random/weaponarena_random.qc
deleted file mode 100644 (file)
index e4d400d..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifdef IMPLEMENTATION
-// WEAPONTODO: rename the cvars
-REGISTER_MUTATOR(weaponarena_random, true);
-
-MUTATOR_HOOKFUNCTION(weaponarena_random, PlayerSpawn)
-{
-    if (!g_weaponarena_random) return;
-    entity player = M_ARGV(0, entity);
-
-    if (g_weaponarena_random_with_blaster) player.weapons &= ~WEPSET(BLASTER);
-    W_RandomWeapons(player, g_weaponarena_random);
-    if (g_weaponarena_random_with_blaster) player.weapons |= WEPSET(BLASTER);
-}
-
-#endif
index e4f082355bd9ad47d184b50a33f11116c26e3d78..dd5f3a164b58502f1b9bdacab31c4f1789145bbf 100644 (file)
@@ -1,3 +1,4 @@
+#include "all.qh"
 #if defined(CSQC)
        #include <client/announcer.qh>
 #elif defined(MENUQC)
@@ -7,8 +8,7 @@
        #include <server/autocvars.qh>
        #include <server/constants.qh>
        #include <server/defs.qh>
-       #include "all.qh"
-       #include <server/mutators/all.qh>
+       #include <server/mutators/_mod.qh>
 #endif
 
 // ================================================
@@ -1532,8 +1532,8 @@ void Kill_Notification(
        net_notif.nent_net_name = ORDINAL(net_cpid);
        Net_LinkEntity(net_notif, false, autocvar_notification_lifetime_runtime, Net_Write_Notification);
 
-       FOREACH_ENTITY_CLASS(
-               "net_notification",
+       IL_EACH(
+               g_notifications,
                (it.owner.nent_type == net_type || net_type == MSG_Null) && (it.owner.nent_cpid == net_cpid || net_cpid == CPID_Null),
                {
                        it.nent_net_name = -1;
@@ -1682,6 +1682,7 @@ void Send_Notification(
        else
        {
                entity net_notif = new_pure(net_notification);
+               IL_PUSH(g_notifications, net_notif);
                net_notif.owner = notif;
                net_notif.nent_broadcast = broadcast;
                net_notif.nent_client = client;
index 983b69f3f4562b3a6a96363ef94543940de4f983..ccdcc690a8148cbc5308221823587225311af3c8 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <common/command/all.qh>
+#include <common/command/_mod.qh>
 
 #include <common/constants.qh>
 #include <common/teams.qh>
@@ -159,7 +159,7 @@ GENERIC_COMMAND(dumpnotifs, "Dump all notifications into notifications_dump.txt"
        {
                case CMD_REQUEST_COMMAND:
                {
-                       #ifndef MENUQC
+                       #ifdef GAMEQC
                        string filename = argv(1);
                        bool alsoprint = false;
                        if (filename == "")
@@ -225,6 +225,11 @@ string prev_soundfile;
 float prev_soundtime;
 #endif
 
+#ifdef SVQC
+IntrusiveList g_notifications;
+STATIC_INIT(g_notifications) { g_notifications = IL_NEW(); }
+#endif
+
 #ifdef SVQC
 ENUMCLASS(NOTIF)
        /** send to one client and their spectators */
index 3a61cd4e9a433c03742c10a5233e4a044f32c181..100aecae29a006bcecf6caf42162815d30f76086 100644 (file)
@@ -1,3 +1,5 @@
 // generated file; do not modify
 #include <common/physics/movelib.qc>
 #include <common/physics/player.qc>
+
+#include <common/physics/movetypes/_mod.inc>
index 39dacad8e2817c9aad232c4b59a8348df012fb7e..377a7b340d8527720af548e8926af06d634a8804 100644 (file)
@@ -1,3 +1,5 @@
 // generated file; do not modify
 #include <common/physics/movelib.qh>
 #include <common/physics/player.qh>
+
+#include <common/physics/movetypes/_mod.qh>
index 51520898705e99e3d9a9c8ca1f7da9a00c948ee3..3009069052f7de48c7a4e7a0fa25f69f993cac21 100644 (file)
@@ -1,3 +1,4 @@
+#include "follow.qh"
 void _Movetype_Physics_Follow(entity this) // SV_Physics_Follow
 {
        entity e = this.aiment;
diff --git a/qcsrc/common/physics/movetypes/follow.qh b/qcsrc/common/physics/movetypes/follow.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 1810fb841d3126ec2b1811915d963da2f9aeaa56..729928bf5b14fff939f22547dc35165c076d841f 100644 (file)
@@ -1,10 +1,10 @@
+#include "movetypes.qh"
 #include "../player.qh"
 
 #if defined(CSQC)
        #include <client/defs.qh>
        #include <common/stats.qh>
        #include <common/util.qh>
-       #include "movetypes.qh"
        #include <lib/csqcmodel/common.qh>
        #include <common/t_items.qh>
 #elif defined(MENUQC)
@@ -19,9 +19,7 @@ void set_movetype(entity this, int mt)
        if (mt == MOVETYPE_PHYSICS || mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH) {
                this.move_qcphysics = false;
        }
-       if (!this.move_qcphysics) {
-               this.movetype = mt;
-       }
+       this.movetype = (this.move_qcphysics) ? MOVETYPE_NONE : mt;
 }
 #elif defined(CSQC)
 void set_movetype(entity this, int mt)
index 7eb553bfaa983cbffc9eb28e352a5a7f2e3ced52..a41269f79c562122fe8f01e6745cfa7df2180748 100644 (file)
@@ -1,3 +1,4 @@
+#include "step.qh"
 void _Movetype_Physics_Step(entity this, float dt) // SV_Physics_Step
 {
        if(IS_ONGROUND(this))
diff --git a/qcsrc/common/physics/movetypes/step.qh b/qcsrc/common/physics/movetypes/step.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 4821e34f6ac8929ae610ddc00ab35cd188223ce6..498852135b40fd0607ee78d1b86daff703e48ac5 100644 (file)
@@ -1,3 +1,4 @@
+#include "toss.qh"
 #include "../player.qh"
 
 void _Movetype_Physics_Toss(entity this, float dt)  // SV_Physics_Toss
diff --git a/qcsrc/common/physics/movetypes/toss.qh b/qcsrc/common/physics/movetypes/toss.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index bf58ca5824419938d4b7ff5dd598273507860516..c20e82e8342825a9282142d288281ceffea2583d 100644 (file)
@@ -1,3 +1,4 @@
+#include "walk.qh"
 void _Movetype_Physics_Walk(entity this, float dt)  // SV_WalkMove
 {
        vector stepnormal = '0 0 0';
diff --git a/qcsrc/common/physics/movetypes/walk.qh b/qcsrc/common/physics/movetypes/walk.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 4fe8c88f516bc9425abc6b3ac0a2e5dd7c2a597d..f5c0e0316e3340bb995e04577ad9719375c063b8 100644 (file)
@@ -80,44 +80,6 @@ float GeomLerp(float a, float _lerp, float b)
                : a * pow(fabs(b / a), _lerp);
 }
 
-#define unstick_offsets(X) \
-/* 1 no nudge (just return the original if this test passes) */ \
-       X(' 0.000  0.000  0.000') \
-/* 6 simple nudges */ \
-       X(' 0.000  0.000  0.125') X('0.000  0.000 -0.125') \
-       X('-0.125  0.000  0.000') X('0.125  0.000  0.000') \
-       X(' 0.000 -0.125  0.000') X('0.000  0.125  0.000') \
-/* 4 diagonal flat nudges */ \
-       X('-0.125 -0.125  0.000') X('0.125 -0.125  0.000') \
-       X('-0.125  0.125  0.000') X('0.125  0.125  0.000') \
-/* 8 diagonal upward nudges */ \
-       X('-0.125  0.000  0.125') X('0.125  0.000  0.125') \
-       X(' 0.000 -0.125  0.125') X('0.000  0.125  0.125') \
-       X('-0.125 -0.125  0.125') X('0.125 -0.125  0.125') \
-       X('-0.125  0.125  0.125') X('0.125  0.125  0.125') \
-/* 8 diagonal downward nudges */ \
-       X('-0.125  0.000 -0.125') X('0.125  0.000 -0.125') \
-       X(' 0.000 -0.125 -0.125') X('0.000  0.125 -0.125') \
-       X('-0.125 -0.125 -0.125') X('0.125 -0.125 -0.125') \
-       X('-0.125  0.125 -0.125') X('0.125  0.125 -0.125') \
-/**/
-
-void PM_ClientMovement_Unstick(entity this)
-{
-       #define X(unstick_offset) \
-       { \
-               vector neworigin = unstick_offset + this.origin; \
-               tracebox(neworigin, STAT(PL_CROUCH_MIN, NULL), STAT(PL_CROUCH_MAX, NULL), neworigin, MOVE_NORMAL, this); \
-               if (!trace_startsolid) \
-               { \
-                       setorigin(this, neworigin); \
-                       return; \
-               } \
-       }
-       unstick_offsets(X);
-       #undef X
-}
-
 void PM_ClientMovement_UpdateStatus(entity this)
 {
 #ifdef CSQC
index ad58221269f0466b1733733a2b925982f10a5504..4dab61164e4b3f7e94b6a2880df0f1d232269e9d 100644 (file)
@@ -1,12 +1,12 @@
+#include "playerstats.qh"
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
     #include "constants.qh"
     #include "util.qh"
-    #include <common/weapons/all.qh>
+    #include <common/weapons/_all.qh>
     #include "../server/weapons/accuracy.qh"
     #include "../server/defs.qh"
-    #include "playerstats.qh"
     #include "../server/scores.qh"
 #endif
 
index 9096dddfa8c0e6a31dd1dc2d3f5f8ba069df4b56..b3bdf99e9177e765d1280e880fa6b5ecdef1fbed 100644 (file)
@@ -1,3 +1,4 @@
+#include "all.qh"
 #ifdef SVQC
 
 bool autocvar_bot_sound_monopoly;
index c8822926f2bd7892df35470dd543836e635ec83d..d6aa068ea67eb775da3cba979c9a62398e9cbcf2 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 #ifdef SVQC
-#include <server/cl_client.qh>
+#include <server/client.qh>
 #endif
 
 // Full list of all stat constants, included in a single location for easy reference
index bc914d853da3594145faeb8d21e7cc653cbb241b..f9f89a73fa6ec8a5da6bf70d62227079c8569d5d 100644 (file)
@@ -1,12 +1,12 @@
 #include "t_items.qh"
 
-#include "items/all.qc"
+#include "items/_mod.qh"
 
 #if defined(SVQC)
 
     #include "../server/bot/api.qh"
 
-    #include <server/mutators/all.qh>
+    #include <server/mutators/_mod.qh>
 
     #include "../server/weapons/common.qh"
     #include "../server/weapons/selection.qh"
        #include "triggers/subs.qh"
     #include "util.qh"
 
-    #include <common/monsters/all.qh>
+    #include <common/monsters/_mod.qh>
 
-    #include <common/weapons/all.qh>
+    #include <common/weapons/_all.qh>
 
     #include "../lib/warpzone/util_server.qh"
 #elif defined(CSQC)
        #include "physics/movetypes/movetypes.qh"
-       #include <common/weapons/all.qh>
+       #include <common/weapons/_all.qh>
        #include "../lib/csqcmodel/cl_model.qh"
        #include "../lib/csqcmodel/common.qh"
 #endif
@@ -835,10 +835,9 @@ LABEL(pickup)
                if(this.team)
                {
                        RandomSelection_Init();
-                       FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
+                       IL_EACH(g_items, it.team == this.team,
                        {
-                               if(it.team == this.team)
-                               if(it.classname != "item_flag_team" && it.classname != "item_key_team")
+                               if(it.classname != "item_flag_team" && it.classname != "item_kh_key")
                                {
                                        Item_Show(it, -1);
                                        RandomSelection_Add(it, 0, string_null, it.cnt, 0);
@@ -880,10 +879,9 @@ void Item_FindTeam(entity this)
                // marker for item team search
                LOG_TRACE("Initializing item team ", ftos(this.team));
                RandomSelection_Init();
-               FOREACH_ENTITY_FLOAT(team, this.team,
+               IL_EACH(g_items, it.team == this.team,
                {
-                       if(it.flags & FL_ITEM)
-                       if(it.classname != "item_flag_team" && it.classname != "item_key_team")
+                       if(it.classname != "item_flag_team" && it.classname != "item_kh_key")
                                RandomSelection_Add(it, 0, string_null, it.cnt, 0);
                });
 
@@ -891,10 +889,9 @@ void Item_FindTeam(entity this)
                e.state = 0;
                Item_Show(e, 1);
 
-               FOREACH_ENTITY_FLOAT(team, this.team,
+               IL_EACH(g_items, it.team == this.team,
                {
-                       if(it.flags & FL_ITEM)
-                       if(it.classname != "item_flag_team" && it.classname != "item_key_team")
+                       if(it.classname != "item_flag_team" && it.classname != "item_kh_key")
                        {
                                if(it != e)
                                {
@@ -1076,6 +1073,7 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
                this.weapons = WepSet_FromWeapon(Weapons_from(weaponid));
 
        this.flags = FL_ITEM | itemflags;
+       IL_PUSH(g_items, this);
 
        if(MUTATOR_CALLHOOK(FilterItem, this)) // error means we do not want the item
        {
@@ -1447,10 +1445,9 @@ void target_items_use(entity this, entity actor, entity trigger)
                EXACTTRIGGER_TOUCH(this, trigger);
        }
 
-       FOREACH_ENTITY_ENT(enemy, actor,
+       IL_EACH(g_items, it.enemy == actor && it.classname == "droppedweapon",
        {
-               if(it.classname == "droppedweapon")
-                       delete(it);
+               delete(it);
        });
 
        if(GiveItems(actor, 0, tokenize_console(this.netname)))
index c049b10828d94f28669e578f2e2d53ce082f307f..9b327de55d23fc0f59fbc9e8b7a34e267ccbcaf1 100644 (file)
@@ -4,3 +4,8 @@
 #include <common/triggers/subs.qc>
 #include <common/triggers/teleporters.qc>
 #include <common/triggers/triggers.qc>
+
+#include <common/triggers/func/_mod.inc>
+#include <common/triggers/misc/_mod.inc>
+#include <common/triggers/target/_mod.inc>
+#include <common/triggers/trigger/_mod.inc>
index 2fba6046172541db1c2324c936fd81f8d57eecaa..d3bb2dc3addb2764d6a6cd71e6f8ee115b305160 100644 (file)
@@ -4,3 +4,8 @@
 #include <common/triggers/subs.qh>
 #include <common/triggers/teleporters.qh>
 #include <common/triggers/triggers.qh>
+
+#include <common/triggers/func/_mod.qh>
+#include <common/triggers/misc/_mod.qh>
+#include <common/triggers/target/_mod.qh>
+#include <common/triggers/trigger/_mod.qh>
index 094673b5bb4612f0b2dcb25f9b0afb7840ca42b0..b7034939ae8863806fc49fb2d326488e70d2a84f 100644 (file)
@@ -1,3 +1,4 @@
+#include "bobbing.qh"
 #ifdef SVQC
 .float height;
 void func_bobbing_controller_think(entity this)
diff --git a/qcsrc/common/triggers/func/bobbing.qh b/qcsrc/common/triggers/func/bobbing.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 29d6c6a269ec3d4181a3ae8a9bb168b7e8682c50..13094e790aa527db25853d5a7f72944490c2b57b 100644 (file)
@@ -1,3 +1,4 @@
+#include "breakable.qh"
 #ifdef SVQC
 
 #include <server/g_subs.qh>
@@ -133,6 +134,8 @@ void func_breakable_behave_destroyed(entity this)
 {
        this.health = this.max_health;
        this.takedamage = DAMAGE_NO;
+       if(this.bot_attack)
+               IL_REMOVE(g_bot_targets, this);
        this.bot_attack = false;
        this.event_damage = func_null;
        this.state = 1;
@@ -154,6 +157,8 @@ void func_breakable_behave_restore(entity this)
        if(!(this.spawnflags & 4))
        {
                this.takedamage = DAMAGE_AIM;
+               if(!this.bot_attack)
+                       IL_PUSH(g_bot_targets, this);
                this.bot_attack = true;
                this.event_damage = func_breakable_damage;
        }
@@ -350,7 +355,7 @@ spawnfunc(func_breakable)
        this.reset = func_breakable_reset;
        this.reset(this);
 
-       this.init_for_player_needed = 1;
+       IL_PUSH(g_initforplayer, this);
        this.init_for_player = func_breakable_init_for_player;
 
        CSQCMODEL_AUTOINIT(this);
index b186066e602b1523586a6d4f299a162445ee7efa..916ff8ca1f1434c4f5053f995484df4bcb43cec2 100644 (file)
@@ -1,3 +1,4 @@
+#include "button.qh"
 #ifdef SVQC
 // button and multiple button
 
diff --git a/qcsrc/common/triggers/func/button.qh b/qcsrc/common/triggers/func/button.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 73ceb639408ea20361504d6489d80fc569223a12..90328da23002dd61a1a8cc37fb9b6c93705fb7d9 100644 (file)
@@ -1,3 +1,4 @@
+#include "conveyor.qh"
 REGISTER_NET_LINKED(ENT_CLIENT_CONVEYOR)
 
 void conveyor_think(entity this)
@@ -10,9 +11,10 @@ void conveyor_think(entity this)
 #endif
 
        // set mythis as current conveyor where possible
-       FOREACH_ENTITY_ENT(conveyor, this,
+       IL_EACH(g_conveyed, it.conveyor == this,
        {
                it.conveyor = NULL;
+               IL_REMOVE(g_conveyed, it);
        });
 
        if(this.state)
@@ -28,10 +30,14 @@ void conveyor_think(entity this)
                        }
                        if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
                                if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, it)) // accurate
+                               {
+                                       if(!it.conveyor)
+                                               IL_PUSH(g_conveyed, it);
                                        it.conveyor = this;
+                               }
                });
 
-               FOREACH_ENTITY_ENT(conveyor, this,
+               IL_EACH(g_conveyed, it.conveyor == this,
                {
                        if(IS_CLIENT(it)) // doing it via velocity has quite some advantages
                                continue; // done in SV_PlayerPhysics   continue;
diff --git a/qcsrc/common/triggers/func/conveyor.qh b/qcsrc/common/triggers/func/conveyor.qh
new file mode 100644 (file)
index 0000000..c12b52d
--- /dev/null
@@ -0,0 +1,4 @@
+#pragma once
+
+IntrusiveList g_conveyed;
+STATIC_INIT(g_conveyed) { g_conveyed = IL_NEW(); }
index 706784eda7b18b13918269cbece6bad46d0bc3eb..8a82802607bdcdb09f505d11248419d5e4d20977 100644 (file)
@@ -1,3 +1,4 @@
+#include "door.qh"
 /*
 
 Doors are similar to buttons, but can spawn a fat trigger field around them
index 31171899fc691a889e204ff06cee003b68b21bea..2c72dc9cf07c1b249d91648683f0e3f4396017a9 100644 (file)
@@ -1,3 +1,4 @@
+#include "door_rotating.qh"
 #ifdef SVQC
 /*QUAKED spawnfunc_func_door_rotating (0 .5 .8) ? START_OPEN BIDIR DOOR_DONT_LINK BIDIR_IN_DOWN x TOGGLE X_AXIS Y_AXIS
 if two doors touch, they are assumed to be connected and operate as a unit.
diff --git a/qcsrc/common/triggers/func/door_rotating.qh b/qcsrc/common/triggers/func/door_rotating.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 600949fe5c0528f598c0c7692108cae2578058f9..0b8930aec5a494aca16a3a889a5b02fdb2df8bf9 100644 (file)
@@ -1,3 +1,4 @@
+#include "door_secret.qh"
 #ifdef SVQC
 void fd_secret_move1(entity this);
 void fd_secret_move2(entity this);
@@ -19,6 +20,8 @@ void fd_secret_use(entity this, entity actor, entity trigger)
        string message_save;
 
        this.health = 10000;
+       if(!this.bot_attack)
+               IL_PUSH(g_bot_targets, this);
        this.bot_attack = true;
 
        // exit if still moving around...
diff --git a/qcsrc/common/triggers/func/door_secret.qh b/qcsrc/common/triggers/func/door_secret.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 52eab115a0655790538c6c43471dabaafbe32be8..600f3937301fdbd6695e1272e1623bfbd76ea41b 100644 (file)
@@ -1,3 +1,4 @@
+#include "fourier.qh"
 #ifdef SVQC
 /*QUAKED spawnfunc_func_fourier (0 .5 .8) ?
 Brush model that moves in a pattern of added up sine waves, can be used e.g. for circular motions.
diff --git a/qcsrc/common/triggers/func/fourier.qh b/qcsrc/common/triggers/func/fourier.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index ae9160dfdab1300e6e0aa0142dc08fdc848dae54..5ff2bdcc247133ac99b9c7a95f1ae4da3fe38a82 100644 (file)
@@ -1,3 +1,4 @@
+#include "ladder.qh"
 REGISTER_NET_LINKED(ENT_CLIENT_LADDER)
 
 void func_ladder_touch(entity this, entity toucher)
index 05f7b75a67602ead968210b1bcf94343d4c32d3c..946712509b0fbea3b1a5752cdcf6da94531a3e3e 100644 (file)
@@ -1,3 +1,4 @@
+#include "pendulum.qh"
 #ifdef SVQC
 .float freq;
 void func_pendulum_controller_think(entity this)
diff --git a/qcsrc/common/triggers/func/pendulum.qh b/qcsrc/common/triggers/func/pendulum.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 396636e8cd214cf8c96e8f7f95b0ae90a920e192..5d90924daa248b0e079f8ff4bc99bf5b6c4e125e 100644 (file)
@@ -1,3 +1,4 @@
+#include "plat.qh"
 REGISTER_NET_LINKED(ENT_CLIENT_PLAT)
 
 #ifdef SVQC
diff --git a/qcsrc/common/triggers/func/plat.qh b/qcsrc/common/triggers/func/plat.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 0cf0615da8e66fae26ea186239ede6f0c28ca7b0..a0773f249a82ccfe6bc52f0fac17cb063381cbd6 100644 (file)
@@ -1,3 +1,4 @@
+#include "pointparticles.qh"
 REGISTER_NET_LINKED(ENT_CLIENT_POINTPARTICLES)
 
 #ifdef SVQC
diff --git a/qcsrc/common/triggers/func/pointparticles.qh b/qcsrc/common/triggers/func/pointparticles.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index cc7dc09228b872efe428a0704d62764e353f6889..c8b4e2924376fb510b27ba4ffb2c6d4dc1cba511 100644 (file)
@@ -1,3 +1,4 @@
+#include "rainsnow.qh"
 REGISTER_NET_LINKED(ENT_CLIENT_RAINSNOW)
 
 #ifdef SVQC
diff --git a/qcsrc/common/triggers/func/rainsnow.qh b/qcsrc/common/triggers/func/rainsnow.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 22f3dedea282926edb76fd55ec172d740aad02af..1adaea91d354db13b259a0109fb86da46efd3352 100644 (file)
@@ -1,3 +1,4 @@
+#include "rotating.qh"
 #ifdef SVQC
 void func_rotating_setactive(entity this, int astate)
 {
diff --git a/qcsrc/common/triggers/func/rotating.qh b/qcsrc/common/triggers/func/rotating.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index db5081b61b474659b09a7f98f0cd58742d98f86f..9c2fba8ada8ed27ca928ba17218beadffcd70111 100644 (file)
@@ -1,3 +1,4 @@
+#include "stardust.qh"
 #ifdef SVQC
 spawnfunc(func_stardust)
 {
diff --git a/qcsrc/common/triggers/func/stardust.qh b/qcsrc/common/triggers/func/stardust.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 247bfb0fc1e5e34703fc23f42e751e0d57be681a..dd9eaac860a5efe24dc0f7d09b71569b356f5fc2 100644 (file)
@@ -1,3 +1,4 @@
+#include "train.qh"
 .float train_wait_turning;
 void train_next(entity this);
 #ifdef SVQC
index accdc998350a556af775d72eac796ef9675abfb2..18d58d649177124543cec55d6834644e99ec58f9 100644 (file)
@@ -1,3 +1,4 @@
+#include "vectormamamam.qh"
 #ifdef SVQC
 // reusing some fields havocbots declared
 .entity wp00, wp01, wp02, wp03;
diff --git a/qcsrc/common/triggers/func/vectormamamam.qh b/qcsrc/common/triggers/func/vectormamamam.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index f3f81738a19f7a73106863b91a90a0bee7c47c3d..87c07c14df58db888f78d5cd293de5830bd37676 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 // some required common stuff
-#ifdef CSQC
+#ifdef SVQC
        #include <server/item_key.qh>
 #endif
 #include "triggers.qh"
index 38772a295562e09ec2138f05f7e54dec1a445e79..dcc44710fc4e2fe6f746d3c8fd85b0d8da06f7de 100644 (file)
@@ -1,3 +1,4 @@
+#include "corner.qh"
 REGISTER_NET_LINKED(ENT_CLIENT_CORNER)
 
 #ifdef SVQC
diff --git a/qcsrc/common/triggers/misc/corner.qh b/qcsrc/common/triggers/misc/corner.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index d19d9da0853c856dd5132dff40fa42d22945c042..63db2c18fa83ac172f62dce5a7b187fccc0c63c4 100644 (file)
@@ -1,3 +1,4 @@
+#include "follow.qh"
 // the way this entity works makes it no use to CSQC, as it removes itself instantly
 
 #ifdef SVQC
diff --git a/qcsrc/common/triggers/misc/follow.qh b/qcsrc/common/triggers/misc/follow.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 8965c62906e01e349fb2b5f85867746414907878..bbe5ce03d6d18fca6344507904a0c22dac1d081e 100644 (file)
@@ -1,3 +1,4 @@
+#include "include.qh"
 #include "corner.qc"
 #include "follow.qc"
 #include "laser.qc"
diff --git a/qcsrc/common/triggers/misc/include.qh b/qcsrc/common/triggers/misc/include.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index d10ff11280b2aa82efd6babfd450c7e996786422..2059a8126d53101672aec3410e6560e8812d2891 100644 (file)
@@ -1,3 +1,4 @@
+#include "laser.qh"
 #if defined(CSQC)
        #include <lib/csqcmodel/interpolate.qh>
        #include <client/main.qh>
diff --git a/qcsrc/common/triggers/misc/laser.qh b/qcsrc/common/triggers/misc/laser.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index ab15a689192c50ac21e2c639b54c3d26f951d8ac..fc3cec863a26920d0547df1143e75af283631f88 100644 (file)
@@ -1,3 +1,4 @@
+#include "teleport_dest.qh"
 REGISTER_NET_LINKED(ENT_CLIENT_TELEPORT_DEST)
 
 #ifdef SVQC
diff --git a/qcsrc/common/triggers/misc/teleport_dest.qh b/qcsrc/common/triggers/misc/teleport_dest.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 7b9ffd9c5007d573e724e8c0462c83698bbc2ccd..10af3e1944316a7f1b6299297cfbd6a3686cb3d3 100644 (file)
@@ -1,3 +1,4 @@
+#include "platforms.qh"
 void generic_plat_blocked(entity this, entity blocker)
 {
 #ifdef SVQC
index 66f0253d95e1bcce3987fc33c2f1f50943905e4b..67eb18a6782b84f54abedd8813e258c51b846fb4 100644 (file)
@@ -1,3 +1,4 @@
+#include "subs.qh"
 void SUB_NullThink(entity this) { }
 
 void SUB_CalcMoveDone(entity this);
index d4bc850de11eef0766ec3aeeefca3aca59ac75e6..6c006d42a91610e70cd3984bc076cdc61312885c 100644 (file)
@@ -1,3 +1,4 @@
+#include "changelevel.qh"
 #ifdef SVQC
 .string chmap, gametype;
 .entity chlevel_targ;
diff --git a/qcsrc/common/triggers/target/changelevel.qh b/qcsrc/common/triggers/target/changelevel.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 5a24d2c5ed6e4e709ba4d2b5d445b1905e59ab23..5259276e43c0f1bb7c47ae87ea9365577e89bbc8 100644 (file)
@@ -1,3 +1,4 @@
+#include "location.qh"
 #ifdef SVQC
 void target_push_init(entity this);
 
diff --git a/qcsrc/common/triggers/target/location.qh b/qcsrc/common/triggers/target/location.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index ff195f03f9bff35a12f6adad94dfe66e1cec8656..0fde9e043904d00f4093fe74bcc45a9ce0a74b52 100644 (file)
@@ -1,3 +1,4 @@
+#include "music.qh"
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
@@ -11,6 +12,9 @@ REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_MUSIC)
 
 #ifdef SVQC
 
+IntrusiveList g_targetmusic_list;
+STATIC_INIT(g_targetmusic_list) { g_targetmusic_list = IL_NEW(); }
+
 // values:
 //   volume
 //   noise
@@ -36,7 +40,8 @@ void target_music_reset(entity this)
 }
 void target_music_kill()
 {
-       FOREACH_ENTITY_CLASS("target_music", true, {
+       IL_EACH(g_targetmusic_list, true,
+       {
                it.volume = 0;
         if (it.targetname == "")
             target_music_sendto(it, MSG_ALL, 1);
@@ -64,6 +69,7 @@ spawnfunc(target_music)
        this.reset = target_music_reset;
        if(!this.volume)
                this.volume = 1;
+       IL_PUSH(g_targetmusic_list, this);
        if(this.targetname == "")
                target_music_sendto(this, MSG_INIT, 1);
        else
@@ -71,7 +77,7 @@ spawnfunc(target_music)
 }
 void TargetMusic_RestoreGame()
 {
-       FOREACH_ENTITY_CLASS("target_music", true,
+       IL_EACH(g_targetmusic_list, true,
        {
                if(it.targetname == "")
                        target_music_sendto(it, MSG_INIT, 1);
index bc5271040c691516623d68240c241faad5fb6b32..4eed8ef345872f3726bcb03fd4904fdcb63a871e 100644 (file)
@@ -1,3 +1,4 @@
+#include "spawn.qh"
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
diff --git a/qcsrc/common/triggers/target/spawn.qh b/qcsrc/common/triggers/target/spawn.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index f8f1c0ace5d32f38da5e6f3086b1f82011618eab..af327b443bc21febb1c8494829bfd10e1fb4543a 100644 (file)
@@ -1,3 +1,4 @@
+#include "speaker.qh"
 #ifdef SVQC
 // TODO add a way to do looped sounds with sound(); then complete this entity
 void target_speaker_use_off(entity this, entity actor, entity trigger);
diff --git a/qcsrc/common/triggers/target/speaker.qh b/qcsrc/common/triggers/target/speaker.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index bdf1e0f1fb40e856f89823b0d3e347aae9a3be03..fe7155cc546ff60349f4ed22b164a5ca313ca73c 100644 (file)
@@ -1,3 +1,4 @@
+#include "voicescript.qh"
 #ifdef SVQC
 .entity voicescript; // attached voice script
 .float voicescript_index; // index of next voice, or -1 to use the randomized ones
diff --git a/qcsrc/common/triggers/target/voicescript.qh b/qcsrc/common/triggers/target/voicescript.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index a1a38d39e1a95e24459d2a2c4c1a5bb857c7de27..b5e97b1fc7516f1a082a82d69c354a85f4b8594e 100644 (file)
@@ -267,10 +267,10 @@ void teleport_findtarget(entity this)
 
 entity Teleport_Find(vector mi, vector ma)
 {
-       entity e;
-       for(e = NULL; (e = find(e, classname, "trigger_teleport")); )
-               if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, NULL))
-                       return e;
+       IL_EACH(g_teleporters, WarpZoneLib_BoxTouchesBrush(mi, ma, it, NULL),
+       {
+               return it;
+       });
        return NULL;
 }
 
index 513ed3e26928460e636b36940fa0d009c5213241..6f5f8cb76e21bec6f941b85e2aebccd767b5ba21 100644 (file)
@@ -1,5 +1,8 @@
 #pragma once
 
+IntrusiveList g_teleporters;
+STATIC_INIT(g_teleporters) { g_teleporters = IL_NEW(); }
+
 .entity pusher;
 const float TELEPORT_FLAG_SOUND = 1;
 const float TELEPORT_FLAG_PARTICLES = 2;
index a4f850ba9ad548d9b76e14f67f64fd6f4851054a..8246aed7c329a67c8eaa10cf3f4822186ba62cfc 100644 (file)
@@ -1,3 +1,4 @@
+#include "counter.qh"
 #ifdef SVQC
 void counter_use(entity this, entity actor, entity trigger)
 {
diff --git a/qcsrc/common/triggers/trigger/counter.qh b/qcsrc/common/triggers/trigger/counter.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index d6742fed3298c03f70882ee07871ed566a54beb5..c5049da3931f73b8eab4288601d30fd71426d25a 100644 (file)
@@ -1,3 +1,4 @@
+#include "delay.qh"
 #ifdef SVQC
 void delay_use(entity this, entity actor, entity trigger)
 {
diff --git a/qcsrc/common/triggers/trigger/delay.qh b/qcsrc/common/triggers/trigger/delay.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 1d30db0e08f919a703a1d11da5d5b35bb0369802..6154f6bf0aa073e67c3aa522bb7a96501c541f6a 100644 (file)
@@ -1,3 +1,4 @@
+#include "disablerelay.qh"
 #ifdef SVQC
 void trigger_disablerelay_use(entity this, entity actor, entity trigger)
 {
diff --git a/qcsrc/common/triggers/trigger/disablerelay.qh b/qcsrc/common/triggers/trigger/disablerelay.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index e4923bdf545bdf8cb43740858ffc384071191539..af212ff5a42b7449bea067a2c755d4c86374782f 100644 (file)
@@ -1,3 +1,4 @@
+#include "flipflop.qh"
 #ifdef SVQC
 /*QUAKED spawnfunc_trigger_flipflop (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ENABLED
 "Flip-flop" trigger gate... lets only every second trigger event through
diff --git a/qcsrc/common/triggers/trigger/flipflop.qh b/qcsrc/common/triggers/trigger/flipflop.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 62b21e66f4fe4dbe8bcc5010c83e1b6c1500ce8d..72d76d183326437bdd4f5bcd7a38393d0a578268 100644 (file)
@@ -1,3 +1,4 @@
+#include "gamestart.qh"
 #ifdef SVQC
 void gamestart_use(entity this, entity actor, entity trigger)
 {
diff --git a/qcsrc/common/triggers/trigger/gamestart.qh b/qcsrc/common/triggers/trigger/gamestart.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 88b73c4dfcdd1d15c979c3bf2cebda4172ce0020..3ea1562f084a93e4c73b7fdb0c9a26ac64dad90e 100644 (file)
@@ -1,3 +1,4 @@
+#include "gravity.qh"
 #ifdef SVQC
 .entity trigger_gravity_check;
 void trigger_gravity_remove(entity own)
diff --git a/qcsrc/common/triggers/trigger/gravity.qh b/qcsrc/common/triggers/trigger/gravity.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 5a2bc78de8a16017afc95b71b8be8d2fa643f24a..e7b309062848d0fe673b8d797f4039512f292372 100644 (file)
@@ -1,3 +1,4 @@
+#include "heal.qh"
 #ifdef SVQC
 .float triggerhealtime;
 void trigger_heal_touch(entity this, entity toucher)
diff --git a/qcsrc/common/triggers/trigger/heal.qh b/qcsrc/common/triggers/trigger/heal.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 4579fd7524af53601118a5e3e11f2c57dc780f58..d0ba4ebd19b252e925e425bb6cd2089475cffeff 100644 (file)
@@ -1,3 +1,4 @@
+#include "hurt.qh"
 #ifdef SVQC
 void trigger_hurt_use(entity this, entity actor, entity trigger)
 {
diff --git a/qcsrc/common/triggers/trigger/hurt.qh b/qcsrc/common/triggers/trigger/hurt.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 43bac947e127908930ca816e0f9115b82b5f4127..cb9c2d293558fad6829c7e888a08c9cfc63c0f40 100644 (file)
@@ -1,3 +1,4 @@
+#include "impulse.qh"
 // targeted (directional) mode
 void trigger_impulse_touch1(entity this, entity toucher)
 {
index 519ba2691586fb5e5d0d99a99021361310b8c5bb..ef13dd5bec0d95af57d2432ba25e83953335cfa5 100644 (file)
@@ -1,3 +1,4 @@
+#include "jumppads.qh"
 // TODO: split target_push and put it in the target folder
 #ifdef SVQC
 #include "jumppads.qh"
index eabb84f57ac4bb5c06960e855659ba34a1bbce96..bf20d1e9732e4dfe133ed4fc5473ae50b5021bd9 100644 (file)
@@ -1,3 +1,4 @@
+#include "keylock.qh"
 /**
  * trigger given targets
  */
index 53fda30e4285bfb27d74113dbe343288a40248da..065d8c932ac1ffdd04c2cf0b1054cf231877b6d4 100644 (file)
@@ -1,3 +1,4 @@
+#include "magicear.qh"
 #ifdef SVQC
 float magicear_matched;
 float W_Tuba_HasPlayed(entity pl, string melody, float instrument, float ignorepitch, float mintempo, float maxtempo);
diff --git a/qcsrc/common/triggers/trigger/magicear.qh b/qcsrc/common/triggers/trigger/magicear.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 018e20884b25938e7d17fba6fc0764948c2aad1d..a67baca16a2f152d69877823eee144bfd076724a 100644 (file)
@@ -1,3 +1,4 @@
+#include "monoflop.qh"
 #ifdef SVQC
 /*QUAKED spawnfunc_trigger_monoflop (.5 .5 .5) (-8 -8 -8) (8 8 8)
 "Mono-flop" trigger gate... turns one trigger event into one "on" and one "off" event, separated by a delay of "wait"
diff --git a/qcsrc/common/triggers/trigger/monoflop.qh b/qcsrc/common/triggers/trigger/monoflop.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index b801e9f4f35cb169470cd0c87e62061ae19bb3f3..7aa13c13ebfc2aec22b8d7a7382607877cd0d5e2 100644 (file)
@@ -1,3 +1,4 @@
+#include "multi.qh"
 // NOTE: also contains trigger_once at bottom
 
 #ifdef SVQC
index 1a1850537d4f29cd7bdde118395ea007e1d1716d..d946efe5f17cc533c2b104b52fb1dc2c2e37ba82 100644 (file)
@@ -1,3 +1,4 @@
+#include "multivibrator.qh"
 #ifdef SVQC
 void multivibrator_send(entity this)
 {
diff --git a/qcsrc/common/triggers/trigger/multivibrator.qh b/qcsrc/common/triggers/trigger/multivibrator.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 1df446ba32ee4345a936fc0512c98eb5aa191a65..794f4dc112d017a4e9759dbe84095d628662602e 100644 (file)
@@ -1,3 +1,4 @@
+#include "relay.qh"
 #ifdef SVQC
 /*QUAKED spawnfunc_trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
 This fixed size trigger cannot be touched, it can only be fired by other events.  It can contain killtargets, targets, delays, and messages.
diff --git a/qcsrc/common/triggers/trigger/relay.qh b/qcsrc/common/triggers/trigger/relay.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index bbb49d0e5c29a3aafe79595510a684666fd25a27..d713a05837728245f18a604f96647b5a300d40ca 100644 (file)
@@ -1,3 +1,4 @@
+#include "relay_activators.qh"
 #ifdef SVQC
 void relay_activators_use(entity this, entity actor, entity trigger)
 {
diff --git a/qcsrc/common/triggers/trigger/relay_activators.qh b/qcsrc/common/triggers/trigger/relay_activators.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index ea90a06cb70d19865b24365bf582ebfbcadcfaee..728252c70400972a4259b3f49eea02c5100027d2 100644 (file)
@@ -1,3 +1,4 @@
+#include "relay_if.qh"
 #ifdef SVQC
 void trigger_relay_if_use(entity this, entity actor, entity trigger)
 {
diff --git a/qcsrc/common/triggers/trigger/relay_if.qh b/qcsrc/common/triggers/trigger/relay_if.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 2972d32bbf79b3e23fa6da66e4e9569e982a6824..4f9dab7fd1e500a4228297b82ba9e6dab1be6dc6 100644 (file)
@@ -1,3 +1,4 @@
+#include "relay_teamcheck.qh"
 #ifdef SVQC
 void trigger_relay_teamcheck_use(entity this, entity actor, entity trigger)
 {
diff --git a/qcsrc/common/triggers/trigger/relay_teamcheck.qh b/qcsrc/common/triggers/trigger/relay_teamcheck.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 9260c01ac2817e1f6920139f1f7b9c1c42895056..e6e35c295a9f8d723285699de7db0972e850ea9c 100644 (file)
@@ -1,9 +1,9 @@
+#include "secret.qh"
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
     #include <common/util.qh>
     #include <server/defs.qh>
-    #include "secret.qh"
 #endif
 
 #ifdef SVQC
index 99eb846c7305be7dafb0c711bfd28637241c3eed..71c5247c7446c5332d12e62b7f9084e105e47bd9 100644 (file)
@@ -1,8 +1,9 @@
+#include "swamp.qh"
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
     #include <lib/warpzone/util_server.qh>
-    #include <common/weapons/all.qh>
+    #include <common/weapons/_all.qh>
     #include <server/defs.qh>
     #include <common/deathtypes/all.qh>
 #endif
index 69e2c49c1d9c83b3ceb2b13fb3a14bc9f96e8f65..c3de654609ff5e0db36ad1bf01e4b314b3283023 100644 (file)
@@ -1,3 +1,4 @@
+#include "teleport.qh"
 REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_TELEPORT)
 
 #ifdef SVQC
@@ -98,6 +99,8 @@ spawnfunc(trigger_teleport)
                return;
        }
 
+       IL_PUSH(g_teleporters, this);
+
        this.teleport_next = teleport_first;
        teleport_first = this;
 }
@@ -105,6 +108,8 @@ spawnfunc(trigger_teleport)
 NET_HANDLE(ENT_CLIENT_TRIGGER_TELEPORT, bool isnew)
 {
        this.classname = "trigger_teleport";
+       if(isnew)
+               IL_PUSH(g_teleporters, this);
        int mytm = ReadByte(); if(mytm) { this.team = mytm - 1; }
        this.spawnflags = ReadInt24_t();
        this.active = ReadByte();
diff --git a/qcsrc/common/triggers/trigger/teleport.qh b/qcsrc/common/triggers/trigger/teleport.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index f2a0e86cc33be9aadae80058f36ddd603e53ac0b..d53ac5dca6720b9d3669088704da27e04e9bd744 100644 (file)
@@ -1,3 +1,4 @@
+#include "viewloc.qh"
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
index 81144aae7f883b382cdf903aabd6cc64e32ca084..54e1e09919f06666bb6ff1b22c379b5f7577bc0c 100644 (file)
@@ -1,3 +1,4 @@
+#include "triggers.qh"
 void SUB_DontUseTargets(entity this, entity actor, entity trigger) { }
 
 void SUB_UseTargets(entity this, entity actor, entity trigger);
index bc4047fe93785fb194e91b3f257adaf755283ace..2b8274f4b890aa473b5432de2415bb1719e925a1 100644 (file)
@@ -28,8 +28,6 @@ string trigger_magicear_processmessage_forallears(entity source, float teamsay,
 void target_voicescript_next(entity pl);
 void target_voicescript_clear(entity pl);
 
-void SUB_ForEachTarget_Init();
-void SUB_ForEachTarget(entity s, void(entity, float, vector, string, entity) cback, float recursive, float fdata, vector vdata, string sdata, entity edata);
 void SUB_UseTargets_PreventReuse(entity this, entity actor, entity trigger);
 #endif
 
diff --git a/qcsrc/common/turrets/_all.inc b/qcsrc/common/turrets/_all.inc
new file mode 100644 (file)
index 0000000..8bc63f7
--- /dev/null
@@ -0,0 +1,2 @@
+#include "_all.qh"
+#include "_mod.inc"
diff --git a/qcsrc/common/turrets/_all.qh b/qcsrc/common/turrets/_all.qh
new file mode 100644 (file)
index 0000000..947026d
--- /dev/null
@@ -0,0 +1,2 @@
+#pragma once
+#include "_mod.qh"
index 40c3114bab5983451be09892c943a8c4ba83170d..8fff9535c5ce40ca345d9175a859b509dd053218 100644 (file)
@@ -1,8 +1,13 @@
 // generated file; do not modify
 #include <common/turrets/all.qc>
 #include <common/turrets/checkpoint.qc>
-#include <common/turrets/cl_turrets.qc>
 #include <common/turrets/config.qc>
-#include <common/turrets/sv_turrets.qc>
 #include <common/turrets/targettrigger.qc>
+#include <common/turrets/turrets.qc>
+#ifdef CSQC
+    #include <common/turrets/cl_turrets.qc>
+#endif
+#ifdef SVQC
+    #include <common/turrets/sv_turrets.qc>
+#endif
 #include <common/turrets/util.qc>
index 6da539e8522ac3ac979eb28aafc8861747cc4780..06978f1d41e23fa375a94ab19463287553d0736c 100644 (file)
@@ -1,8 +1,13 @@
 // generated file; do not modify
 #include <common/turrets/all.qh>
 #include <common/turrets/checkpoint.qh>
-#include <common/turrets/cl_turrets.qh>
 #include <common/turrets/config.qh>
-#include <common/turrets/sv_turrets.qh>
 #include <common/turrets/targettrigger.qh>
+#include <common/turrets/turrets.qh>
+#ifdef CSQC
+    #include <common/turrets/cl_turrets.qh>
+#endif
+#ifdef SVQC
+    #include <common/turrets/sv_turrets.qh>
+#endif
 #include <common/turrets/util.qh>
index 476da2d18e0423d7c242963fc14408ff3e7d7ad1..1a77e989121b0cade1ab49e584f93e6e575b29d4 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <common/command/all.qh>
+#include <common/command/_mod.qh>
 #include "config.qh"
 
 #include "turret.qh"
index fb56d3ecc93026e892066e1d193d9030791bb3c1..6c246a75b83a5c8b6229f475c32c82bd173f1556 100644 (file)
@@ -1,3 +1,4 @@
+#include "checkpoint.qh"
 /**
     turret_checkpoint
 **/
diff --git a/qcsrc/common/turrets/checkpoint.qh b/qcsrc/common/turrets/checkpoint.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 29658b56b459ade61ef0f89a2e8a3f58fed3d2ec..a893b3e8a77d30c281ef602770dc6098319947f6 100644 (file)
@@ -1,3 +1,4 @@
+#include "cl_turrets.qh"
 void turret_remove(entity this)
 {
        delete(this.tur_head);
diff --git a/qcsrc/common/turrets/cl_turrets.qh b/qcsrc/common/turrets/cl_turrets.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index f5989b48d157221c0e1fea3b629e3ee8911b6c4f..2b1e00c8a7d29d9db05b175bd357b4547786c480 100644 (file)
@@ -1,3 +1,4 @@
+#include "config.qh"
 // ==========================
 //  Turret Config Generator
 // ==========================
index a387fefc47c459797da84069f3476fbe5dd0ffe8..c90eaff1fe98fdb22bc7918fefedd1f28c703738 100644 (file)
@@ -1,3 +1,4 @@
+#include "sv_turrets.qh"
 #ifdef SVQC
 #include <server/autocvars.qh>
 
@@ -478,6 +479,7 @@ entity turret_projectile(entity actor, Sound _snd, float _size, float _health, f
        proj.velocity           = normalize(actor.tur_shotdir_updated + randomvec() * actor.shot_spread) * actor.shot_speed;
        proj.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, proj);
+       IL_PUSH(g_bot_dodge, proj);
        proj.enemy                = actor.enemy;
        proj.totalfrags  = _death;
        PROJECTILE_MAKETRIGGER(proj);
@@ -1251,6 +1253,7 @@ bool turret_initialize(entity this, Turret tur)
        if(!this.tur_head) {
                tur.tr_precache(tur);
                IL_PUSH(g_turrets, this);
+               IL_PUSH(g_bot_targets, this);
        }
 
        entity e = find(NULL, classname, "turret_manager");
index ca94f2b4e1fbee55b2a219b1959d2f5bd8c9c94f..152a7d6a2715e362fde40fca3be8f20497ccc511 100644 (file)
@@ -1,10 +1,12 @@
+#include "targettrigger.qh"
 spawnfunc(turret_targettrigger);
 void turret_targettrigger_touch(entity this, entity toucher);
 
 void turret_targettrigger_touch(entity this, entity toucher)
 {
     if (this.cnt > time) return;
-    FOREACH_ENTITY_STRING_ORDERED(targetname, this.target, {
+    IL_EACH(g_turrets, it.targetname == this.target,
+    {
         if (!(it.turret_flags & TUR_FLAG_RECIEVETARGETS)) continue;
         if (!it.turret_addtarget) continue;
         it.turret_addtarget(it, toucher, this);
diff --git a/qcsrc/common/turrets/targettrigger.qh b/qcsrc/common/turrets/targettrigger.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 649fd51ae697eb4454871b8aa063cb1612f49419..8e5239702866c4c6fe4519a7c34d67f2aa00b7fd 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 
 CLASS(Turret, Object)
     ATTRIB(Turret, m_id, int, 0);
index a86acdb274d8ba99c45c53f3dba3ec59d216c593..b5716f7a9867195973b98d95ffa254d883da85a6 100644 (file)
@@ -1,24 +1,4 @@
-#ifndef TURRET_EWHEEL_H
-#define TURRET_EWHEEL_H
-
-//#define EWHEEL_FANCYPATH
-
-#include "ewheel_weapon.qh"
-
-CLASS(EWheel, Turret)
-/* spawnflags */ ATTRIB(EWheel, spawnflags, int, TUR_FLAG_PLAYER | TUR_FLAG_MOVE | TUR_FLAG_ROAM);
-/* mins       */ ATTRIB(EWheel, mins, vector, '-32 -32 0');
-/* maxs       */ ATTRIB(EWheel, maxs, vector, '32 32 48');
-/* modelname  */ ATTRIB(EWheel, mdl, string, "ewheel-base2.md3");
-/* model      */ ATTRIB_STRZONE(EWheel, model, string, strcat("models/turrets/", this.mdl));
-/* head_model */ ATTRIB_STRZONE(EWheel, head_model, string, strcat("models/turrets/", "ewheel-gun1.md3"));
-/* netname    */ ATTRIB(EWheel, netname, string, "ewheel");
-/* fullname   */ ATTRIB(EWheel, turret_name, string, _("eWheel Turret"));
-    ATTRIB(EWheel, m_weapon, Weapon, WEP_EWHEEL);
-ENDCLASS(EWheel)
-REGISTER_TURRET(EWHEEL, NEW(EWheel));
-
-#endif
+#include "ewheel.qh"
 
 #ifdef IMPLEMENTATION
 
diff --git a/qcsrc/common/turrets/turret/ewheel.qh b/qcsrc/common/turrets/turret/ewheel.qh
new file mode 100644 (file)
index 0000000..b34adb2
--- /dev/null
@@ -0,0 +1,18 @@
+#pragma once
+
+//#define EWHEEL_FANCYPATH
+
+#include "ewheel_weapon.qh"
+
+CLASS(EWheel, Turret)
+/* spawnflags */ ATTRIB(EWheel, spawnflags, int, TUR_FLAG_PLAYER | TUR_FLAG_MOVE | TUR_FLAG_ROAM);
+/* mins       */ ATTRIB(EWheel, mins, vector, '-32 -32 0');
+/* maxs       */ ATTRIB(EWheel, maxs, vector, '32 32 48');
+/* modelname  */ ATTRIB(EWheel, mdl, string, "ewheel-base2.md3");
+/* model      */ ATTRIB_STRZONE(EWheel, model, string, strcat("models/turrets/", this.mdl));
+/* head_model */ ATTRIB_STRZONE(EWheel, head_model, string, strcat("models/turrets/", "ewheel-gun1.md3"));
+/* netname    */ ATTRIB(EWheel, netname, string, "ewheel");
+/* fullname   */ ATTRIB(EWheel, turret_name, string, _("eWheel Turret"));
+    ATTRIB(EWheel, m_weapon, Weapon, WEP_EWHEEL);
+ENDCLASS(EWheel)
+REGISTER_TURRET(EWHEEL, NEW(EWheel));
index 20eeb7759589b5d415a386b141954ce9e1456e5b..ab6e5f5cb67afe9bec1f43fb0adf6a88df0a309f 100644 (file)
@@ -1,22 +1,4 @@
-#ifndef TURRET_FLAC_H
-#define TURRET_FLAC_H
-
-#include "flac_weapon.qh"
-
-CLASS(Flac, Turret)
-/* spawnflags */ ATTRIB(Flac, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_FASTPROJ | TUR_FLAG_MISSILE);
-/* mins       */ ATTRIB(Flac, mins, vector, '-32 -32 0');
-/* maxs       */ ATTRIB(Flac, maxs, vector, '32 32 64');
-/* modelname  */ ATTRIB(Flac, mdl, string, "base.md3");
-/* model      */ ATTRIB_STRZONE(Flac, model, string, strcat("models/turrets/", this.mdl));
-/* head_model */ ATTRIB_STRZONE(Flac, head_model, string, strcat("models/turrets/", "flac.md3"));
-/* netname    */ ATTRIB(Flac, netname, string, "flac");
-/* fullname   */ ATTRIB(Flac, turret_name, string, _("FLAC Cannon"));
-    ATTRIB(Flac, m_weapon, Weapon, WEP_FLAC);
-ENDCLASS(Flac)
-REGISTER_TURRET(FLAC, NEW(Flac));
-
-#endif
+#include "flac.qh"
 
 #ifdef IMPLEMENTATION
 
diff --git a/qcsrc/common/turrets/turret/flac.qh b/qcsrc/common/turrets/turret/flac.qh
new file mode 100644 (file)
index 0000000..d53422c
--- /dev/null
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "flac_weapon.qh"
+
+CLASS(Flac, Turret)
+/* spawnflags */ ATTRIB(Flac, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_FASTPROJ | TUR_FLAG_MISSILE);
+/* mins       */ ATTRIB(Flac, mins, vector, '-32 -32 0');
+/* maxs       */ ATTRIB(Flac, maxs, vector, '32 32 64');
+/* modelname  */ ATTRIB(Flac, mdl, string, "base.md3");
+/* model      */ ATTRIB_STRZONE(Flac, model, string, strcat("models/turrets/", this.mdl));
+/* head_model */ ATTRIB_STRZONE(Flac, head_model, string, strcat("models/turrets/", "flac.md3"));
+/* netname    */ ATTRIB(Flac, netname, string, "flac");
+/* fullname   */ ATTRIB(Flac, turret_name, string, _("FLAC Cannon"));
+    ATTRIB(Flac, m_weapon, Weapon, WEP_FLAC);
+ENDCLASS(Flac)
+REGISTER_TURRET(FLAC, NEW(Flac));
index cd7dbec72d34bc62fc573875d4244eb767694c55..163bffb9d70ebd8988f9f595b75b622c450bd605 100644 (file)
@@ -1,19 +1,4 @@
-#ifndef TURRET_FUSIONREACTOR_H
-#define TURRET_FUSIONREACTOR_H
-
-CLASS(FusionReactor, Turret)
-/* spawnflags */ ATTRIB(FusionReactor, spawnflags, int, TUR_FLAG_SUPPORT | TUR_FLAG_AMMOSOURCE);
-/* mins       */ ATTRIB(FusionReactor, mins, vector, '-34 -34 0');
-/* maxs       */ ATTRIB(FusionReactor, maxs, vector, '34 34 90');
-/* modelname  */ ATTRIB(FusionReactor, mdl, string, "base.md3");
-/* model      */ ATTRIB_STRZONE(FusionReactor, model, string, strcat("models/turrets/", this.mdl));
-/* head_model */ ATTRIB_STRZONE(FusionReactor, head_model, string, strcat("models/turrets/", "reactor.md3"));
-/* netname    */ ATTRIB(FusionReactor, netname, string, "fusionreactor");
-/* fullname   */ ATTRIB(FusionReactor, turret_name, string, _("Fusion Reactor"));
-ENDCLASS(FusionReactor)
-REGISTER_TURRET(FUSIONREACTOR, NEW(FusionReactor));
-
-#endif
+#include "fusionreactor.qh"
 
 #ifdef IMPLEMENTATION
 #ifdef SVQC
diff --git a/qcsrc/common/turrets/turret/fusionreactor.qh b/qcsrc/common/turrets/turret/fusionreactor.qh
new file mode 100644 (file)
index 0000000..134b805
--- /dev/null
@@ -0,0 +1,13 @@
+#pragma once
+
+CLASS(FusionReactor, Turret)
+/* spawnflags */ ATTRIB(FusionReactor, spawnflags, int, TUR_FLAG_SUPPORT | TUR_FLAG_AMMOSOURCE);
+/* mins       */ ATTRIB(FusionReactor, mins, vector, '-34 -34 0');
+/* maxs       */ ATTRIB(FusionReactor, maxs, vector, '34 34 90');
+/* modelname  */ ATTRIB(FusionReactor, mdl, string, "base.md3");
+/* model      */ ATTRIB_STRZONE(FusionReactor, model, string, strcat("models/turrets/", this.mdl));
+/* head_model */ ATTRIB_STRZONE(FusionReactor, head_model, string, strcat("models/turrets/", "reactor.md3"));
+/* netname    */ ATTRIB(FusionReactor, netname, string, "fusreac");
+/* fullname   */ ATTRIB(FusionReactor, turret_name, string, _("Fusion Reactor"));
+ENDCLASS(FusionReactor)
+REGISTER_TURRET(FUSIONREACTOR, NEW(FusionReactor));
index 61203ddf75cb5a599a517251e76d3636f5e0311f..88a0170ea67d4d556f7dd8a72c483615d0af8016 100644 (file)
@@ -1,22 +1,4 @@
-#ifndef TURRET_HELLION_H
-#define TURRET_HELLION_H
-
-#include "hellion_weapon.qh"
-
-CLASS(Hellion, Turret)
-/* spawnflags */ ATTRIB(Hellion, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_FASTPROJ | TUR_FLAG_PLAYER | TUR_FLAG_MISSILE);
-/* mins       */ ATTRIB(Hellion, mins, vector, '-32 -32 0');
-/* maxs       */ ATTRIB(Hellion, maxs, vector, '32 32 64');
-/* modelname  */ ATTRIB(Hellion, mdl, string, "base.md3");
-/* model      */ ATTRIB_STRZONE(Hellion, model, string, strcat("models/turrets/", this.mdl));
-/* head_model */ ATTRIB_STRZONE(Hellion, head_model, string, strcat("models/turrets/", "hellion.md3"));
-/* netname    */ ATTRIB(Hellion, netname, string, "hellion");
-/* fullname   */ ATTRIB(Hellion, turret_name, string, _("Hellion Missile Turret"));
-    ATTRIB(Hellion, m_weapon, Weapon, WEP_HELLION);
-ENDCLASS(Hellion)
-REGISTER_TURRET(HELLION, NEW(Hellion));
-
-#endif
+#include "hellion.qh"
 
 #ifdef IMPLEMENTATION
 
diff --git a/qcsrc/common/turrets/turret/hellion.qh b/qcsrc/common/turrets/turret/hellion.qh
new file mode 100644 (file)
index 0000000..642645b
--- /dev/null
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "hellion_weapon.qh"
+
+CLASS(Hellion, Turret)
+/* spawnflags */ ATTRIB(Hellion, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_FASTPROJ | TUR_FLAG_PLAYER | TUR_FLAG_MISSILE);
+/* mins       */ ATTRIB(Hellion, mins, vector, '-32 -32 0');
+/* maxs       */ ATTRIB(Hellion, maxs, vector, '32 32 64');
+/* modelname  */ ATTRIB(Hellion, mdl, string, "base.md3");
+/* model      */ ATTRIB_STRZONE(Hellion, model, string, strcat("models/turrets/", this.mdl));
+/* head_model */ ATTRIB_STRZONE(Hellion, head_model, string, strcat("models/turrets/", "hellion.md3"));
+/* netname    */ ATTRIB(Hellion, netname, string, "hellion");
+/* fullname   */ ATTRIB(Hellion, turret_name, string, _("Hellion Missile Turret"));
+    ATTRIB(Hellion, m_weapon, Weapon, WEP_HELLION);
+ENDCLASS(Hellion)
+REGISTER_TURRET(HELLION, NEW(Hellion));
index 9cb60df4c63a227932d91be5bb7d5b716db05523..255821e1c368209aa8d229703f6c5dedcc8ec7ba 100644 (file)
@@ -1,24 +1,4 @@
-#ifndef TURRET_HK_H
-#define TURRET_HK_H
-
-//#define TURRET_DEBUG_HK
-
-#include "hk_weapon.qh"
-
-CLASS(HunterKiller, Turret)
-/* spawnflags */ ATTRIB(HunterKiller, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER | TUR_FLAG_RECIEVETARGETS);
-/* mins       */ ATTRIB(HunterKiller, mins, vector, '-32 -32 0');
-/* maxs       */ ATTRIB(HunterKiller, maxs, vector, '32 32 64');
-/* modelname  */ ATTRIB(HunterKiller, mdl, string, "base.md3");
-/* model      */ ATTRIB_STRZONE(HunterKiller, model, string, strcat("models/turrets/", this.mdl));
-/* head_model */ ATTRIB_STRZONE(HunterKiller, head_model, string, strcat("models/turrets/", "hk.md3"));
-/* netname    */ ATTRIB(HunterKiller, netname, string, "hk");
-/* fullname   */ ATTRIB(HunterKiller, turret_name, string, _("Hunter-Killer Turret"));
-    ATTRIB(HunterKiller, m_weapon, Weapon, WEP_HK);
-ENDCLASS(HunterKiller)
-REGISTER_TURRET(HK, NEW(HunterKiller));
-
-#endif
+#include "hk.qh"
 
 #ifdef IMPLEMENTATION
 
diff --git a/qcsrc/common/turrets/turret/hk.qh b/qcsrc/common/turrets/turret/hk.qh
new file mode 100644 (file)
index 0000000..d7c9cfb
--- /dev/null
@@ -0,0 +1,18 @@
+#pragma once
+
+//#define TURRET_DEBUG_HK
+
+#include "hk_weapon.qh"
+
+CLASS(HunterKiller, Turret)
+/* spawnflags */ ATTRIB(HunterKiller, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER | TUR_FLAG_RECIEVETARGETS);
+/* mins       */ ATTRIB(HunterKiller, mins, vector, '-32 -32 0');
+/* maxs       */ ATTRIB(HunterKiller, maxs, vector, '32 32 64');
+/* modelname  */ ATTRIB(HunterKiller, mdl, string, "base.md3");
+/* model      */ ATTRIB_STRZONE(HunterKiller, model, string, strcat("models/turrets/", this.mdl));
+/* head_model */ ATTRIB_STRZONE(HunterKiller, head_model, string, strcat("models/turrets/", "hk.md3"));
+/* netname    */ ATTRIB(HunterKiller, netname, string, "hk");
+/* fullname   */ ATTRIB(HunterKiller, turret_name, string, _("Hunter-Killer Turret"));
+    ATTRIB(HunterKiller, m_weapon, Weapon, WEP_HK);
+ENDCLASS(HunterKiller)
+REGISTER_TURRET(HK, NEW(HunterKiller));
index 8addd9542802a4c07cf80c750187cada65fafcdf..db3cb47bf2fbb6cc3d173ccce2edba39f3ea6072 100644 (file)
@@ -1,22 +1,4 @@
-#ifndef TURRET_MACHINEGUN_H
-#define TURRET_MACHINEGUN_H
-
-#include "machinegun_weapon.qh"
-
-CLASS(MachineGunTurret, Turret)
-/* spawnflags */ ATTRIB(MachineGunTurret, spawnflags, int, TUR_FLAG_PLAYER);
-/* mins       */ ATTRIB(MachineGunTurret, mins, vector, '-32 -32 0');
-/* maxs       */ ATTRIB(MachineGunTurret, maxs, vector, '32 32 64');
-/* modelname  */ ATTRIB(MachineGunTurret, mdl, string, "base.md3");
-/* model      */ ATTRIB_STRZONE(MachineGunTurret, model, string, strcat("models/turrets/", this.mdl));
-/* head_model */ ATTRIB_STRZONE(MachineGunTurret, head_model, string, strcat("models/turrets/", "machinegun.md3"));
-/* netname    */ ATTRIB(MachineGunTurret, netname, string, "machinegun");
-/* fullname   */ ATTRIB(MachineGunTurret, turret_name, string, _("Machinegun Turret"));
-    ATTRIB(MachineGunTurret, m_weapon, Weapon, WEP_TUR_MACHINEGUN);
-ENDCLASS(MachineGunTurret)
-REGISTER_TURRET(MACHINEGUN, NEW(MachineGunTurret));
-
-#endif
+#include "machinegun.qh"
 
 #ifdef IMPLEMENTATION
 
diff --git a/qcsrc/common/turrets/turret/machinegun.qh b/qcsrc/common/turrets/turret/machinegun.qh
new file mode 100644 (file)
index 0000000..92a8fba
--- /dev/null
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "machinegun_weapon.qh"
+
+CLASS(MachineGunTurret, Turret)
+/* spawnflags */ ATTRIB(MachineGunTurret, spawnflags, int, TUR_FLAG_PLAYER);
+/* mins       */ ATTRIB(MachineGunTurret, mins, vector, '-32 -32 0');
+/* maxs       */ ATTRIB(MachineGunTurret, maxs, vector, '32 32 64');
+/* modelname  */ ATTRIB(MachineGunTurret, mdl, string, "base.md3");
+/* model      */ ATTRIB_STRZONE(MachineGunTurret, model, string, strcat("models/turrets/", this.mdl));
+/* head_model */ ATTRIB_STRZONE(MachineGunTurret, head_model, string, strcat("models/turrets/", "machinegun.md3"));
+/* netname    */ ATTRIB(MachineGunTurret, netname, string, "machinegun");
+/* fullname   */ ATTRIB(MachineGunTurret, turret_name, string, _("Machinegun Turret"));
+    ATTRIB(MachineGunTurret, m_weapon, Weapon, WEP_TUR_MACHINEGUN);
+ENDCLASS(MachineGunTurret)
+REGISTER_TURRET(MACHINEGUN, NEW(MachineGunTurret));
index 316d3b9a0589f9d4941c962ee365cc20c5ede8c7..472a0cb09a5c410ad5ae5a7060e410799189ccd4 100644 (file)
@@ -1,22 +1,4 @@
-#ifndef TURRET_MLRS_H
-#define TURRET_MLRS_H
-
-#include "mlrs_weapon.qh"
-
-CLASS(MLRSTurret, Turret)
-/* spawnflags */ ATTRIB(MLRSTurret, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER);
-/* mins       */ ATTRIB(MLRSTurret, mins, vector, '-32 -32 0');
-/* maxs       */ ATTRIB(MLRSTurret, maxs, vector, '32 32 64');
-/* modelname  */ ATTRIB(MLRSTurret, mdl, string, "base.md3");
-/* model      */ ATTRIB_STRZONE(MLRSTurret, model, string, strcat("models/turrets/", this.mdl));
-/* head_model */ ATTRIB_STRZONE(MLRSTurret, head_model, string, strcat("models/turrets/", "mlrs.md3"));
-/* netname    */ ATTRIB(MLRSTurret, netname, string, "mlrs");
-/* fullname   */ ATTRIB(MLRSTurret, turret_name, string, _("MLRS Turret"));
-    ATTRIB(MLRSTurret, m_weapon, Weapon, WEP_TUR_MLRS);
-ENDCLASS(MLRSTurret)
-REGISTER_TURRET(MLRS, NEW(MLRSTurret));
-
-#endif
+#include "mlrs.qh"
 
 #ifdef IMPLEMENTATION
 
diff --git a/qcsrc/common/turrets/turret/mlrs.qh b/qcsrc/common/turrets/turret/mlrs.qh
new file mode 100644 (file)
index 0000000..b2a6a5c
--- /dev/null
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "mlrs_weapon.qh"
+
+CLASS(MLRSTurret, Turret)
+/* spawnflags */ ATTRIB(MLRSTurret, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER);
+/* mins       */ ATTRIB(MLRSTurret, mins, vector, '-32 -32 0');
+/* maxs       */ ATTRIB(MLRSTurret, maxs, vector, '32 32 64');
+/* modelname  */ ATTRIB(MLRSTurret, mdl, string, "base.md3");
+/* model      */ ATTRIB_STRZONE(MLRSTurret, model, string, strcat("models/turrets/", this.mdl));
+/* head_model */ ATTRIB_STRZONE(MLRSTurret, head_model, string, strcat("models/turrets/", "mlrs.md3"));
+/* netname    */ ATTRIB(MLRSTurret, netname, string, "mlrs");
+/* fullname   */ ATTRIB(MLRSTurret, turret_name, string, _("MLRS Turret"));
+    ATTRIB(MLRSTurret, m_weapon, Weapon, WEP_TUR_MLRS);
+ENDCLASS(MLRSTurret)
+REGISTER_TURRET(MLRS, NEW(MLRSTurret));
index 7c5d336212694b662262ee9da99372b2857d6ace..31ece9cb2b8b86d7946d9c0eaf45634910e09036 100644 (file)
@@ -1,22 +1,4 @@
-#ifndef TURRET_PHASER_H
-#define TURRET_PHASER_H
-
-#include "phaser_weapon.qh"
-
-CLASS(PhaserTurret, Turret)
-/* spawnflags */ ATTRIB(PhaserTurret, spawnflags, int, TUR_FLAG_SNIPER | TUR_FLAG_HITSCAN | TUR_FLAG_PLAYER);
-/* mins       */ ATTRIB(PhaserTurret, mins, vector, '-32 -32 0');
-/* maxs       */ ATTRIB(PhaserTurret, maxs, vector, '32 32 64');
-/* modelname  */ ATTRIB(PhaserTurret, mdl, string, "base.md3");
-/* model      */ ATTRIB_STRZONE(PhaserTurret, model, string, strcat("models/turrets/", this.mdl));
-/* head_model */ ATTRIB_STRZONE(PhaserTurret, head_model, string, strcat("models/turrets/", "phaser.md3"));
-/* netname    */ ATTRIB(PhaserTurret, netname, string, "phaser");
-/* fullname   */ ATTRIB(PhaserTurret, turret_name, string, _("Phaser Cannon"));
-    ATTRIB(PhaserTurret, m_weapon, Weapon, WEP_PHASER);
-ENDCLASS(PhaserTurret)
-REGISTER_TURRET(PHASER, NEW(PhaserTurret));
-
-#endif
+#include "phaser.qh"
 
 #ifdef IMPLEMENTATION
 
diff --git a/qcsrc/common/turrets/turret/phaser.qh b/qcsrc/common/turrets/turret/phaser.qh
new file mode 100644 (file)
index 0000000..fedbe66
--- /dev/null
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "phaser_weapon.qh"
+
+CLASS(PhaserTurret, Turret)
+/* spawnflags */ ATTRIB(PhaserTurret, spawnflags, int, TUR_FLAG_SNIPER | TUR_FLAG_HITSCAN | TUR_FLAG_PLAYER);
+/* mins       */ ATTRIB(PhaserTurret, mins, vector, '-32 -32 0');
+/* maxs       */ ATTRIB(PhaserTurret, maxs, vector, '32 32 64');
+/* modelname  */ ATTRIB(PhaserTurret, mdl, string, "base.md3");
+/* model      */ ATTRIB_STRZONE(PhaserTurret, model, string, strcat("models/turrets/", this.mdl));
+/* head_model */ ATTRIB_STRZONE(PhaserTurret, head_model, string, strcat("models/turrets/", "phaser.md3"));
+/* netname    */ ATTRIB(PhaserTurret, netname, string, "phaser");
+/* fullname   */ ATTRIB(PhaserTurret, turret_name, string, _("Phaser Cannon"));
+    ATTRIB(PhaserTurret, m_weapon, Weapon, WEP_PHASER);
+ENDCLASS(PhaserTurret)
+REGISTER_TURRET(PHASER, NEW(PhaserTurret));
index 2e08f5eb3d723cedefe9d790dbea66ee1c572f4e..bf901d886a77e407292d8d208d20f37819f5b8cc 100644 (file)
@@ -36,6 +36,7 @@ METHOD(PhaserTurretAttack, wr_think, void(entity thiswep, entity actor, .entity
         set_movetype(beam, MOVETYPE_NONE);
         beam.enemy = actor.enemy;
         beam.bot_dodge = true;
+        IL_PUSH(g_bot_dodge, beam);
         beam.bot_dodgerating = beam.shot_dmg;
         sound (beam, CH_SHOTS_SINGLE, SND_TUR_PHASER, VOL_BASE, ATTEN_NORM);
         actor.fireflag = 1;
index 82aa1abe67cbf198bfcd51c58e97af98741d5174..d161436ab0807041b4bff31e65205cea02a15264 100644 (file)
@@ -1,22 +1,4 @@
-#ifndef TURRET_PLASMA_H
-#define TURRET_PLASMA_H
-
-#include "plasma_weapon.qh"
-
-CLASS(PlasmaTurret, Turret)
-/* spawnflags */ ATTRIB(PlasmaTurret, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER);
-/* mins       */ ATTRIB(PlasmaTurret, mins, vector, '-32 -32 0');
-/* maxs       */ ATTRIB(PlasmaTurret, maxs, vector, '32 32 64');
-/* modelname  */ ATTRIB(PlasmaTurret, mdl, string, "base.md3");
-/* model      */ ATTRIB_STRZONE(PlasmaTurret, model, string, strcat("models/turrets/", this.mdl));
-/* head_model */ ATTRIB_STRZONE(PlasmaTurret, head_model, string, strcat("models/turrets/", "plasma.md3"));
-/* netname    */ ATTRIB(PlasmaTurret, netname, string, "plasma");
-/* fullname   */ ATTRIB(PlasmaTurret, turret_name, string, _("Plasma Cannon"));
-    ATTRIB(PlasmaTurret, m_weapon, Weapon, WEP_PLASMA);
-ENDCLASS(PlasmaTurret)
-REGISTER_TURRET(PLASMA, NEW(PlasmaTurret));
-
-#endif
+#include "plasma.qh"
 
 #ifdef IMPLEMENTATION
 
diff --git a/qcsrc/common/turrets/turret/plasma.qh b/qcsrc/common/turrets/turret/plasma.qh
new file mode 100644 (file)
index 0000000..fc2a96d
--- /dev/null
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "plasma_weapon.qh"
+
+CLASS(PlasmaTurret, Turret)
+/* spawnflags */ ATTRIB(PlasmaTurret, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER);
+/* mins       */ ATTRIB(PlasmaTurret, mins, vector, '-32 -32 0');
+/* maxs       */ ATTRIB(PlasmaTurret, maxs, vector, '32 32 64');
+/* modelname  */ ATTRIB(PlasmaTurret, mdl, string, "base.md3");
+/* model      */ ATTRIB_STRZONE(PlasmaTurret, model, string, strcat("models/turrets/", this.mdl));
+/* head_model */ ATTRIB_STRZONE(PlasmaTurret, head_model, string, strcat("models/turrets/", "plasma.md3"));
+/* netname    */ ATTRIB(PlasmaTurret, netname, string, "plasma");
+/* fullname   */ ATTRIB(PlasmaTurret, turret_name, string, _("Plasma Cannon"));
+    ATTRIB(PlasmaTurret, m_weapon, Weapon, WEP_PLASMA);
+ENDCLASS(PlasmaTurret)
+REGISTER_TURRET(PLASMA, NEW(PlasmaTurret));
index 9430bc69211147c6fb125330c2b9976c4c7c3d18..9e6d80b2fd830f165117630e685779d19afb82ca 100644 (file)
@@ -1,28 +1,4 @@
-#ifndef TURRET_PLASMA_DUAL_H
-#define TURRET_PLASMA_DUAL_H
-
-#include "plasma_weapon.qh"
-
-CLASS(PlasmaDualAttack, PlasmaAttack)
-/* refname   */ ATTRIB(PlasmaDualAttack, netname, string, "turret_plasma_dual");
-/* wepname   */ ATTRIB(PlasmaDualAttack, m_name, string, _("Dual plasma"));
-ENDCLASS(PlasmaDualAttack)
-REGISTER_WEAPON(PLASMA_DUAL, NEW(PlasmaDualAttack));
-
-CLASS(DualPlasmaTurret, PlasmaTurret)
-/* spawnflags */ ATTRIB(DualPlasmaTurret, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER);
-/* mins       */ ATTRIB(DualPlasmaTurret, mins, vector, '-32 -32 0');
-/* maxs       */ ATTRIB(DualPlasmaTurret, maxs, vector, '32 32 64');
-/* modelname  */ ATTRIB(DualPlasmaTurret, mdl, string, "base.md3");
-/* model      */ ATTRIB_STRZONE(DualPlasmaTurret, model, string, strcat("models/turrets/", this.mdl));
-/* head_model */ ATTRIB_STRZONE(DualPlasmaTurret, head_model, string, strcat("models/turrets/", "plasmad.md3"));
-/* netname    */ ATTRIB(DualPlasmaTurret, netname, string, "plasma_dual");
-/* fullname   */ ATTRIB(DualPlasmaTurret, turret_name, string, _("Dual Plasma Cannon"));
-    ATTRIB(DualPlasmaTurret, m_weapon, Weapon, WEP_PLASMA_DUAL);
-ENDCLASS(DualPlasmaTurret)
-REGISTER_TURRET(PLASMA_DUAL, NEW(DualPlasmaTurret));
-
-#endif
+#include "plasma_dual.qh"
 
 #ifdef IMPLEMENTATION
 
diff --git a/qcsrc/common/turrets/turret/plasma_dual.qh b/qcsrc/common/turrets/turret/plasma_dual.qh
new file mode 100644 (file)
index 0000000..e4c7b0e
--- /dev/null
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "plasma_weapon.qh"
+
+CLASS(PlasmaDualAttack, PlasmaAttack)
+/* refname   */ ATTRIB(PlasmaDualAttack, netname, string, "turret_plasma_dual");
+/* wepname   */ ATTRIB(PlasmaDualAttack, m_name, string, _("Dual plasma"));
+ENDCLASS(PlasmaDualAttack)
+REGISTER_WEAPON(PLASMA_DUAL, NEW(PlasmaDualAttack));
+
+CLASS(DualPlasmaTurret, PlasmaTurret)
+/* spawnflags */ ATTRIB(DualPlasmaTurret, spawnflags, int, TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER);
+/* mins       */ ATTRIB(DualPlasmaTurret, mins, vector, '-32 -32 0');
+/* maxs       */ ATTRIB(DualPlasmaTurret, maxs, vector, '32 32 64');
+/* modelname  */ ATTRIB(DualPlasmaTurret, mdl, string, "base.md3");
+/* model      */ ATTRIB_STRZONE(DualPlasmaTurret, model, string, strcat("models/turrets/", this.mdl));
+/* head_model */ ATTRIB_STRZONE(DualPlasmaTurret, head_model, string, strcat("models/turrets/", "plasmad.md3"));
+/* netname    */ ATTRIB(DualPlasmaTurret, netname, string, "plasma_dual");
+/* fullname   */ ATTRIB(DualPlasmaTurret, turret_name, string, _("Dual Plasma Cannon"));
+    ATTRIB(DualPlasmaTurret, m_weapon, Weapon, WEP_PLASMA_DUAL);
+ENDCLASS(DualPlasmaTurret)
+REGISTER_TURRET(PLASMA_DUAL, NEW(DualPlasmaTurret));
index b0755f32b57d03e0371bb13734df96ca22b41886..249fe18eb92042465d499a947929c672aee49fa3 100644 (file)
@@ -1,22 +1,4 @@
-#ifndef TURRET_TESLA_H
-#define TURRET_TESLA_H
-
-#include "tesla_weapon.qh"
-
-CLASS(TeslaCoil, Turret)
-/* spawnflags */ ATTRIB(TeslaCoil, spawnflags, int, TUR_FLAG_HITSCAN | TUR_FLAG_PLAYER | TUR_FLAG_MISSILE);
-/* mins       */ ATTRIB(TeslaCoil, mins, vector, '-60 -60 0');
-/* maxs       */ ATTRIB(TeslaCoil, maxs, vector, '60 60 128');
-/* modelname  */ ATTRIB(TeslaCoil, mdl, string, "tesla_base.md3");
-/* model      */ ATTRIB_STRZONE(TeslaCoil, model, string, strcat("models/turrets/", this.mdl));
-/* head_model */ ATTRIB_STRZONE(TeslaCoil, head_model, string, strcat("models/turrets/", "tesla_head.md3"));
-/* netname    */ ATTRIB(TeslaCoil, netname, string, "tesla");
-/* fullname   */ ATTRIB(TeslaCoil, turret_name, string, _("Tesla Coil"));
-    ATTRIB(TeslaCoil, m_weapon, Weapon, WEP_TESLA);
-ENDCLASS(TeslaCoil)
-REGISTER_TURRET(TESLA, NEW(TeslaCoil));
-
-#endif
+#include "tesla.qh"
 
 #ifdef IMPLEMENTATION
 
diff --git a/qcsrc/common/turrets/turret/tesla.qh b/qcsrc/common/turrets/turret/tesla.qh
new file mode 100644 (file)
index 0000000..c5f67b1
--- /dev/null
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "tesla_weapon.qh"
+
+CLASS(TeslaCoil, Turret)
+/* spawnflags */ ATTRIB(TeslaCoil, spawnflags, int, TUR_FLAG_HITSCAN | TUR_FLAG_PLAYER | TUR_FLAG_MISSILE);
+/* mins       */ ATTRIB(TeslaCoil, mins, vector, '-60 -60 0');
+/* maxs       */ ATTRIB(TeslaCoil, maxs, vector, '60 60 128');
+/* modelname  */ ATTRIB(TeslaCoil, mdl, string, "tesla_base.md3");
+/* model      */ ATTRIB_STRZONE(TeslaCoil, model, string, strcat("models/turrets/", this.mdl));
+/* head_model */ ATTRIB_STRZONE(TeslaCoil, head_model, string, strcat("models/turrets/", "tesla_head.md3"));
+/* netname    */ ATTRIB(TeslaCoil, netname, string, "tesla");
+/* fullname   */ ATTRIB(TeslaCoil, turret_name, string, _("Tesla Coil"));
+    ATTRIB(TeslaCoil, m_weapon, Weapon, WEP_TESLA);
+ENDCLASS(TeslaCoil)
+REGISTER_TURRET(TESLA, NEW(TeslaCoil));
index 727da27f945aa4ef67a3a58a44504a4380b2e92a..ffba71439ab995198c760c69843a7bfbe1b3e3d7 100644 (file)
@@ -1,24 +1,4 @@
-#ifndef TURRET_WALKER_H
-#define TURRET_WALKER_H
-
-//#define WALKER_FANCYPATHING
-
-#include "walker_weapon.qh"
-
-CLASS(WalkerTurret, Turret)
-/* spawnflags */ ATTRIB(WalkerTurret, spawnflags, int, TUR_FLAG_PLAYER | TUR_FLAG_MOVE);
-/* mins       */ ATTRIB(WalkerTurret, mins, vector, '-70 -70 0');
-/* maxs       */ ATTRIB(WalkerTurret, maxs, vector, '70 70 95');
-/* modelname  */ ATTRIB(WalkerTurret, mdl, string, "walker_body.md3");
-/* model      */ ATTRIB_STRZONE(WalkerTurret, model, string, strcat("models/turrets/", this.mdl));
-/* head_model */ ATTRIB_STRZONE(WalkerTurret, head_model, string, strcat("models/turrets/", "walker_head_minigun.md3"));
-/* netname    */ ATTRIB(WalkerTurret, netname, string, "walker");
-/* fullname   */ ATTRIB(WalkerTurret, turret_name, string, _("Walker Turret"));
-    ATTRIB(WalkerTurret, m_weapon, Weapon, WEP_WALKER);
-ENDCLASS(WalkerTurret)
-REGISTER_TURRET(WALKER, NEW(WalkerTurret));
-
-#endif
+#include "walker.qh"
 
 #ifdef IMPLEMENTATION
 
@@ -261,6 +241,7 @@ void walker_fire_rocket(entity this, vector org)
     settouch(rocket, walker_rocket_touch);
     rocket.flags = FL_PROJECTILE;
     IL_PUSH(g_projectiles, rocket);
+    IL_PUSH(g_bot_dodge, rocket);
     rocket.solid                         = SOLID_BBOX;
     rocket.max_health           = time + 9;
     rocket.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_HEAT;
diff --git a/qcsrc/common/turrets/turret/walker.qh b/qcsrc/common/turrets/turret/walker.qh
new file mode 100644 (file)
index 0000000..54a908b
--- /dev/null
@@ -0,0 +1,18 @@
+#pragma once
+
+//#define WALKER_FANCYPATHING
+
+#include "walker_weapon.qh"
+
+CLASS(WalkerTurret, Turret)
+/* spawnflags */ ATTRIB(WalkerTurret, spawnflags, int, TUR_FLAG_PLAYER | TUR_FLAG_MOVE);
+/* mins       */ ATTRIB(WalkerTurret, mins, vector, '-70 -70 0');
+/* maxs       */ ATTRIB(WalkerTurret, maxs, vector, '70 70 95');
+/* modelname  */ ATTRIB(WalkerTurret, mdl, string, "walker_body.md3");
+/* model      */ ATTRIB_STRZONE(WalkerTurret, model, string, strcat("models/turrets/", this.mdl));
+/* head_model */ ATTRIB_STRZONE(WalkerTurret, head_model, string, strcat("models/turrets/", "walker_head_minigun.md3"));
+/* netname    */ ATTRIB(WalkerTurret, netname, string, "walker");
+/* fullname   */ ATTRIB(WalkerTurret, turret_name, string, _("Walker Turret"));
+    ATTRIB(WalkerTurret, m_weapon, Weapon, WEP_WALKER);
+ENDCLASS(WalkerTurret)
+REGISTER_TURRET(WALKER, NEW(WalkerTurret));
diff --git a/qcsrc/common/turrets/turrets.qc b/qcsrc/common/turrets/turrets.qc
new file mode 100644 (file)
index 0000000..a53f859
--- /dev/null
@@ -0,0 +1 @@
+#include "turrets.qh"
diff --git a/qcsrc/common/turrets/turrets.qh b/qcsrc/common/turrets/turrets.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 8a6a5ee87bc06716cfebceb362af3217420a4476..5fef364580860b256d624eb552b32a13c55fc098 100644 (file)
@@ -1,3 +1,4 @@
+#include "util.qh"
 /*
 * Update this.tur_shotorg by getting up2date bone info
 * NOTICE this func overwrites the global v_forward, v_right and v_up vectors.
index 9cf439f52bdca0e9a33e93bb626246f8ba4a3886..1c1278bfd538ddf3c6c8450bf5a7be7ed349655e 100644 (file)
@@ -18,7 +18,7 @@
     #include "mapinfo.qh"
 #endif
 
-#ifndef MENUQC
+#ifdef GAMEQC
 /*
 * Get "real" origin, in worldspace, even if ent is attached to something else.
 */
@@ -55,8 +55,7 @@ string wordwrap(string s, float l)
        return r;
 }
 
-#ifndef MENUQC
-#ifndef CSQC
+#ifdef SVQC
 entity _wordwrap_buffer_sprint_ent;
 void wordwrap_buffer_sprint(string s)
 {
@@ -80,7 +79,6 @@ void wordwrap_sprint(entity to, string s, float l)
        return;
 }
 #endif
-#endif
 
 #ifndef SVQC
 string draw_UseSkinFor(string pic)
@@ -352,7 +350,7 @@ STATIC_INIT(compressShortVector)
        }
 }
 
-#ifndef MENUQC
+#ifdef GAMEQC
 float CheckWireframeBox(entity forent, vector v0, vector dvx, vector dvy, vector dvz)
 {
        traceline(v0, v0 + dvx, true, forent); if(trace_fraction < 1) return 0;
@@ -399,6 +397,9 @@ string fixPriorityList(string order, float from, float to, float subtract, float
                n = tokenize_console(neworder);
                for(w = to; w >= from; --w)
                {
+                       int wflags = Weapons_from(w).spawnflags;
+                       if((wflags & WEP_FLAG_HIDDEN) && (wflags & WEP_FLAG_MUTATORBLOCKED) && !(wflags & WEP_FLAG_NORMAL))
+                               continue;
                        for(i = 0; i < n; ++i)
                                if(stof(argv(i)) == w)
                                        break;
@@ -448,7 +449,7 @@ string swapInPriorityList(string order, float i, float j)
        return order;
 }
 
-#ifndef MENUQC
+#ifdef GAMEQC
 void get_mi_min_max(float mode)
 {
        vector mi, ma;
@@ -602,7 +603,7 @@ float cvar_settemp(string tmp_cvar, string tmp_value)
                return 0;
        }
 
-       FOREACH_ENTITY_CLASS("saved_cvar_value", it.netname == tmp_cvar,
+       IL_EACH(g_saved_cvars, it.netname == tmp_cvar,
        {
                created_saved_value = -1; // skip creation
                break; // no need to continue
@@ -612,6 +613,7 @@ float cvar_settemp(string tmp_cvar, string tmp_value)
        {
                // creating a new entity to keep track of this cvar
                entity e = new_pure(saved_cvar_value);
+               IL_PUSH(g_saved_cvars, e);
                e.netname = strzone(tmp_cvar);
                e.message = strzone(cvar_string(tmp_cvar));
                created_saved_value = 1;
@@ -660,6 +662,58 @@ int cvar_settemp_restore()
        return j;
 }
 
+bool isCaretEscaped(string theText, float pos)
+{
+       int i = 0;
+       while(pos - i >= 1 && substring(theText, pos - i - 1, 1) == "^")
+               ++i;
+       return (i & 1);
+}
+
+int skipIncompleteTag(string theText, float pos, int len)
+{
+       int i = 0, ch = 0;
+       int tag_start = -1;
+
+       if(substring(theText, pos - 1, 1) == "^")
+       {
+               if(isCaretEscaped(theText, pos - 1) || pos >= len)
+                       return 0;
+
+               ch = str2chr(theText, pos);
+               if(ch >= '0' && ch <= '9')
+                       return 1; // ^[0-9] color code found
+               else if (ch == 'x')
+                       tag_start = pos - 1; // ^x tag found
+               else
+                       return 0;
+       }
+       else
+       {
+               for(i = 2; pos - i >= 0 && i <= 4; ++i)
+               {
+                       if(substring(theText, pos - i, 2) == "^x")
+                       {
+                               tag_start = pos - i; // ^x tag found
+                               break;
+                       }
+               }
+       }
+
+       if(tag_start >= 0)
+       {
+               if(tag_start + 5 < len)
+               if(strstrofs("0123456789abcdefABCDEF", substring(theText, tag_start + 2, 1), 0) >= 0)
+               if(strstrofs("0123456789abcdefABCDEF", substring(theText, tag_start + 3, 1), 0) >= 0)
+               if(strstrofs("0123456789abcdefABCDEF", substring(theText, tag_start + 4, 1), 0) >= 0)
+               {
+                       if(!isCaretEscaped(theText, tag_start))
+                               return 5 - (pos - tag_start); // ^xRGB color code found
+               }
+       }
+       return 0;
+}
+
 float textLengthUpToWidth(string theText, float maxWidth, vector theSize, textLengthUpToWidth_widthFunction_t w)
 {
        // STOP.
@@ -670,57 +724,25 @@ float textLengthUpToWidth(string theText, float maxWidth, vector theSize, textLe
        if(w(theText, theSize) <= maxWidth)
                return strlen(theText); // yeah!
 
+       bool colors = (w("^7", theSize) == 0);
+
        // binary search for right place to cut string
-       float ch;
-       float left, right, middle; // this always works
+       int len, left, right, middle;
        left = 0;
-       right = strlen(theText); // this always fails
+       right = len = strlen(theText);
+       int ofs = 0;
        do
        {
                middle = floor((left + right) / 2);
-               if(w(substring(theText, 0, middle), theSize) <= maxWidth)
-                       left = middle;
+               if(colors)
+                       ofs = skipIncompleteTag(theText, middle, len);
+               if(w(substring(theText, 0, middle + ofs), theSize) <= maxWidth)
+                       left = middle + ofs;
                else
                        right = middle;
        }
        while(left < right - 1);
 
-       if(w("^7", theSize) == 0) // detect color codes support in the width function
-       {
-               // NOTE: when color codes are involved, this binary search is,
-               // mathematically, BROKEN. However, it is obviously guaranteed to
-               // terminate, as the range still halves each time - but nevertheless, it is
-               // guaranteed that it finds ONE valid cutoff place (where "left" is in
-               // range, and "right" is outside).
-
-               // terencehill: the following code detects truncated ^xrgb tags (e.g. ^x or ^x4)
-               // and decrease left on the basis of the chars detected of the truncated tag
-               // Even if the ^xrgb tag is not complete/correct, left is decreased
-               // (sometimes too much but with a correct result)
-               // it fixes also ^[0-9]
-               while(left >= 1 && substring(theText, left-1, 1) == "^")
-                       left-=1;
-
-               if (left >= 2 && substring(theText, left-2, 2) == "^x") // ^x/
-                       left-=2;
-               else if (left >= 3 && substring(theText, left-3, 2) == "^x")
-                       {
-                               ch = str2chr(theText, left-1);
-                               if( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xr/
-                                       left-=3;
-                       }
-               else if (left >= 4 && substring(theText, left-4, 2) == "^x")
-                       {
-                               ch = str2chr(theText, left-2);
-                               if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') )
-                               {
-                                       ch = str2chr(theText, left-1);
-                                       if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xrg/
-                                               left-=4;
-                               }
-                       }
-       }
-
        return left;
 }
 
@@ -734,57 +756,25 @@ float textLengthUpToLength(string theText, float maxWidth, textLengthUpToLength_
        if(w(theText) <= maxWidth)
                return strlen(theText); // yeah!
 
+       bool colors = (w("^7") == 0);
+
        // binary search for right place to cut string
-       float ch;
-       float left, right, middle; // this always works
+       int len, left, right, middle;
        left = 0;
-       right = strlen(theText); // this always fails
+       right = len = strlen(theText);
+       int ofs = 0;
        do
        {
                middle = floor((left + right) / 2);
-               if(w(substring(theText, 0, middle)) <= maxWidth)
-                       left = middle;
+               if(colors)
+                       ofs = skipIncompleteTag(theText, middle, len);
+               if(w(substring(theText, 0, middle + ofs)) <= maxWidth)
+                       left = middle + ofs;
                else
                        right = middle;
        }
        while(left < right - 1);
 
-       if(w("^7") == 0) // detect color codes support in the width function
-       {
-               // NOTE: when color codes are involved, this binary search is,
-               // mathematically, BROKEN. However, it is obviously guaranteed to
-               // terminate, as the range still halves each time - but nevertheless, it is
-               // guaranteed that it finds ONE valid cutoff place (where "left" is in
-               // range, and "right" is outside).
-
-               // terencehill: the following code detects truncated ^xrgb tags (e.g. ^x or ^x4)
-               // and decrease left on the basis of the chars detected of the truncated tag
-               // Even if the ^xrgb tag is not complete/correct, left is decreased
-               // (sometimes too much but with a correct result)
-               // it fixes also ^[0-9]
-               while(left >= 1 && substring(theText, left-1, 1) == "^")
-                       left-=1;
-
-               if (left >= 2 && substring(theText, left-2, 2) == "^x") // ^x/
-                       left-=2;
-               else if (left >= 3 && substring(theText, left-3, 2) == "^x")
-                       {
-                               ch = str2chr(theText, left-1);
-                               if( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xr/
-                                       left-=3;
-                       }
-               else if (left >= 4 && substring(theText, left-4, 2) == "^x")
-                       {
-                               ch = str2chr(theText, left-2);
-                               if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') )
-                               {
-                                       ch = str2chr(theText, left-1);
-                                       if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xrg/
-                                               left-=4;
-                               }
-                       }
-       }
-
        return left;
 }
 
@@ -1113,7 +1103,7 @@ vector decompressShotOrigin(int f)
        return v;
 }
 
-#ifndef MENUQC
+#ifdef GAMEQC
 vector healtharmor_maxdamage(float h, float a, float armorblock, int deathtype)
 {
        // NOTE: we'll always choose the SMALLER value...
@@ -1227,8 +1217,9 @@ float get_model_parameters(string m, float sk)
                get_model_parameters_bone_aimweight[i] = 0;
        }
        get_model_parameters_fixbone = 0;
+       get_model_parameters_hidden = false;
 
-#ifndef MENUQC
+#ifdef GAMEQC
        MUTATOR_CALLHOOK(ClearModelParams);
 #endif
 
@@ -1293,7 +1284,7 @@ float get_model_parameters(string m, float sk)
                        get_model_parameters_bone_upperbody = s;
                if(c == "bone_weapon")
                        get_model_parameters_bone_weapon = s;
-       #ifndef MENUQC
+       #ifdef GAMEQC
                MUTATOR_CALLHOOK(GetModelParams, c, s);
        #endif
                for(int i = 0; i < MAX_AIM_BONES; ++i)
@@ -1304,6 +1295,8 @@ float get_model_parameters(string m, float sk)
                        }
                if(c == "fixbone")
                        get_model_parameters_fixbone = stof(s);
+               if(c == "hidden")
+                       get_model_parameters_hidden = stob(s);
        }
 
        while((s = fgets(fh)))
@@ -1386,7 +1379,7 @@ void m_shutdown()
        cvar_settemp_restore(); // this must be done LAST, but in any case
 }
 
-#ifndef MENUQC
+#ifdef GAMEQC
 .float skeleton_bones_index;
 void Skeleton_SetBones(entity e)
 {
@@ -1464,7 +1457,7 @@ void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t
                queue_start.FindConnectedComponent_processing = 0;
 }
 
-#ifndef MENUQC
+#ifdef GAMEQC
 vector animfixfps(entity e, vector a, vector b)
 {
        // multi-frame anim: keep as-is
@@ -1483,7 +1476,7 @@ vector animfixfps(entity e, vector a, vector b)
 }
 #endif
 
-#ifndef MENUQC
+#ifdef GAMEQC
 Notification Announcer_PickNumber(int type, int num)
 {
     return = NULL;
@@ -1595,7 +1588,7 @@ Notification Announcer_PickNumber(int type, int num)
 }
 #endif
 
-#ifndef MENUQC
+#ifdef GAMEQC
 int Mod_Q1BSP_SuperContentsFromNativeContents(int nativecontents)
 {
        switch(nativecontents)
index 599dd4d43c5b4bc5abd6f8be6d1a2e28608a0fa4..57f9a2217c42d5a502e8268c139bd8f082094d29 100644 (file)
@@ -1,18 +1,19 @@
 #pragma once
 
-#ifndef MENUQC
+#ifdef GAMEQC
 
 vector real_origin(entity ent);
 #endif
 
+IntrusiveList g_saved_cvars;
+STATIC_INIT(g_saved_cvars) { g_saved_cvars = IL_NEW(); }
+
 // this returns a tempstring containing a copy of s with additional \n newlines added, it also replaces \n in the text with a real newline
 // NOTE: s IS allowed to be a tempstring
 string wordwrap(string s, float l);
-#ifndef MENUQC
-#ifndef CSQC
+#ifdef SVQC
 void wordwrap_sprint(entity to, string s, float l);
 #endif
-#endif
 void wordwrap_cb(string s, float l, void(string) callback);
 
 #ifndef SVQC
@@ -66,7 +67,7 @@ string ScoreString(float vflags, float value);
 vector decompressShortVector(float data);
 float compressShortVector(vector vec);
 
-#ifndef MENUQC
+#ifdef GAMEQC
 float CheckWireframeBox(entity forent, vector v0, vector dvx, vector dvy, vector dvz);
 #endif
 
@@ -79,7 +80,7 @@ float cvar_value_issafe(string s);
 float cvar_settemp(string pKey, string pValue);
 float cvar_settemp_restore();
 
-#ifndef MENUQC
+#ifdef GAMEQC
 // modes: 0 = trust q3map2 (_mini images)
 //        1 = trust tracebox (_radar images)
 // in both modes, mapinfo's "size" overrides
@@ -148,14 +149,14 @@ string rankings_reply, ladder_reply, lsmaps_reply, maplist_reply, monsterlist_re
 string records_reply[10];
 #endif
 
-#ifndef MENUQC
+#ifdef GAMEQC
 vector healtharmor_maxdamage(float h, float a, float armorblock, int deathtype); // returns vector: maxdamage, armorideal, 1 if fully armored
 vector healtharmor_applydamage(float a, float armorblock, int deathtype, float damage); // returns vector: take, save, 0
 #endif
 
 string getcurrentmod();
 
-#ifndef MENUQC
+#ifdef GAMEQC
 #ifdef CSQC
 int ReadInt24_t();
 #else
@@ -180,6 +181,7 @@ float get_model_parameters_species;
 string get_model_parameters_sex;
 float get_model_parameters_weight;
 float get_model_parameters_age;
+bool get_model_parameters_hidden;
 string get_model_parameters_description;
 string get_model_parameters_bone_upperbody;
 string get_model_parameters_bone_weapon;
@@ -190,7 +192,7 @@ float get_model_parameters_fixbone;
 string get_model_parameters_desc;
 float get_model_parameters(string mod, float skn); // call with string_null to clear; skin -1 means mod is the filename of the txt file and is to be split
 
-#ifndef MENUQC
+#ifdef GAMEQC
 vector NearestPointOnBox(entity box, vector org);
 #endif
 
@@ -205,7 +207,7 @@ const float XENCODE_LEN = 5;
 string xencode(float f);
 float xdecode(string s);
 
-#ifndef MENUQC
+#ifdef GAMEQC
 string strtolower(string s);
 #endif
 
@@ -214,7 +216,7 @@ string MakeConsoleSafe(string input);
 // generic shutdown handler
 void Shutdown();
 
-#ifndef MENUQC
+#ifdef GAMEQC
 .float skeleton_bones;
 void Skeleton_SetBones(entity e);
 // loops through the tags of model v using counter tagnum
@@ -256,7 +258,7 @@ void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t
 
 string CCR(string input);
 
-#ifndef MENUQC
+#ifdef GAMEQC
        #ifdef CSQC
                #define GENTLE (autocvar_cl_gentle || autocvar_cl_gentle_messages)
        #else
@@ -265,11 +267,11 @@ string CCR(string input);
        #define normal_or_gentle(normal, gentle) (GENTLE ? ((gentle != "") ? gentle : normal) : normal)
 #endif
 
-#ifndef MENUQC
+#ifdef GAMEQC
 vector animfixfps(entity e, vector a, vector b);
 #endif
 
-#ifndef MENUQC
+#ifdef GAMEQC
 const float CNT_NORMAL = 1;
 const float CNT_GAMESTART = 2;
 const float CNT_IDLE = 3;
@@ -279,7 +281,7 @@ const float CNT_ROUNDSTART = 6;
 entity Announcer_PickNumber(float type, float num);
 #endif
 
-#ifndef MENUQC
+#ifdef GAMEQC
 int Mod_Q1BSP_SuperContentsFromNativeContents(int nativecontents);
 int Mod_Q1BSP_NativeContentsFromSuperContents(int supercontents);
 #endif
diff --git a/qcsrc/common/vehicles/_all.inc b/qcsrc/common/vehicles/_all.inc
new file mode 100644 (file)
index 0000000..8bc63f7
--- /dev/null
@@ -0,0 +1,2 @@
+#include "_all.qh"
+#include "_mod.inc"
diff --git a/qcsrc/common/vehicles/_all.qh b/qcsrc/common/vehicles/_all.qh
new file mode 100644 (file)
index 0000000..947026d
--- /dev/null
@@ -0,0 +1,2 @@
+#pragma once
+#include "_mod.qh"
index 269858f8475ac67cf427be7290191c01c365a8ca..ed26659daa5c9ed37cbb384c8d9a2823e73d6c05 100644 (file)
@@ -1,4 +1,9 @@
 // generated file; do not modify
 #include <common/vehicles/all.qc>
-#include <common/vehicles/cl_vehicles.qc>
-#include <common/vehicles/sv_vehicles.qc>
+#include <common/vehicles/vehicles.qc>
+#ifdef CSQC
+    #include <common/vehicles/cl_vehicles.qc>
+#endif
+#ifdef SVQC
+    #include <common/vehicles/sv_vehicles.qc>
+#endif
index d21e829f7a81cc10c07d372ae501d09313e293f8..4892b0f317baad43e5bc15d6e8fef0d91931f2ff 100644 (file)
@@ -1,4 +1,9 @@
 // generated file; do not modify
 #include <common/vehicles/all.qh>
-#include <common/vehicles/cl_vehicles.qh>
-#include <common/vehicles/sv_vehicles.qh>
+#include <common/vehicles/vehicles.qh>
+#ifdef CSQC
+    #include <common/vehicles/cl_vehicles.qh>
+#endif
+#ifdef SVQC
+    #include <common/vehicles/sv_vehicles.qh>
+#endif
index 251df22839e750646abef244455aa63d7e846df5..4aef11cad56ed35fc49ca0b037842aceb861a74b 100644 (file)
@@ -1,8 +1,7 @@
+#include "all.qh"
 #ifndef VEHICLES_ALL_C
 #define VEHICLES_ALL_C
 
-#include "all.qh"
-
 REGISTER_NET_LINKED(ENT_CLIENT_AUXILIARYXHAIR)
 
 #if defined(SVQC)
index e08490976d15b253e303441933f2b122c69cac4c..afb48c918b89f74e353d3c2f624ecfafdb69e65d 100644 (file)
@@ -1,3 +1,4 @@
+#include "cl_vehicles.qh"
 const string vCROSS_BURST = "gfx/vehicles/crosshair_burst.tga";
 const string vCROSS_DROP  = "gfx/vehicles/crosshair_drop.tga";
 const string vCROSS_GUIDE = "gfx/vehicles/crosshair_guide.tga";
index 39f959d14b9f03f851f6b8edebf6d3efd90008e3..60a8ee07760fbe897e58cd58fab2e22904337728 100644 (file)
@@ -249,6 +249,7 @@ entity vehicles_projectile(entity this, string _mzlfx, Sound _mzlsound,
        set_movetype(proj, MOVETYPE_FLYMISSILE);
        proj.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, proj);
+       IL_PUSH(g_bot_dodge, proj);
        proj.bot_dodge          = true;
        proj.bot_dodgerating  = _dmg;
        proj.velocity            = _vel;
@@ -433,17 +434,15 @@ void vehicles_reset_colors(entity this)
 void vehicles_clearreturn(entity veh)
 {
        // Remove "return helper" entities, if any.
-       FOREACH_ENTITY_ENT(wp00, veh,
+       IL_EACH(g_vehicle_returners, it.wp00 == veh,
        {
-               if(it.classname == "vehicle_return")
-               {
-                       it.classname = "";
-                       setthink(it, SUB_Remove);
-                       it.nextthink = time + 0.1;
+               it.classname = "";
+               setthink(it, SUB_Remove);
+               it.nextthink = time + 0.1;
+               IL_REMOVE(g_vehicle_returners, it);
 
-                       if(it.waypointsprite_attached)
-                               WaypointSprite_Kill(it.waypointsprite_attached);
-               }
+               if(it.waypointsprite_attached)
+                       WaypointSprite_Kill(it.waypointsprite_attached);
        });
 }
 
@@ -513,6 +512,7 @@ void vehicles_setreturn(entity veh)
        vehicles_clearreturn(veh);
 
        entity ret = new(vehicle_return);
+       IL_PUSH(g_vehicle_returners, ret);
        ret.wp00           = veh;
        ret.team                = veh.team;
        setthink(ret, vehicles_showwp);
@@ -1076,6 +1076,8 @@ void vehicles_spawn(entity this)
        this.solid                              = SOLID_SLIDEBOX;
        this.takedamage                 = DAMAGE_AIM;
        this.deadflag                   = DEAD_NO;
+       if(!this.bot_attack)
+               IL_PUSH(g_bot_targets, this);
        this.bot_attack                 = true;
        this.flags                              = FL_NOTARGET;
        this.avelocity                  = '0 0 0';
@@ -1161,6 +1163,7 @@ bool vehicle_initialize(entity this, Vehicle info, bool nodrop)
        this.tur_head.owner                     = this;
        this.takedamage                         = DAMAGE_NO;
        this.bot_attack                         = true;
+       IL_PUSH(g_bot_targets, this);
        this.iscreature                         = true;
        this.teleportable                       = false; // no teleporting for vehicles, too buggy
        this.damagedbycontents          = true;
index 158191f654eed354806d07cf2140d7a6db1176b4..948427db33e0923c8c28af0ddbf61845a2369e32 100644 (file)
@@ -108,4 +108,7 @@ bool vehicle_impulse(entity this, int imp);
 bool vehicles_crushable(entity e);
 float vehicle_altitude(entity this, float amax);
 
+IntrusiveList g_vehicle_returners;
+STATIC_INIT(g_vehicle_returners) { g_vehicle_returners = IL_NEW(); }
+
 #endif
index 9f718e34b98a1ec28f22a8c01acf60970468ba85..403c9de9ddb1bb73a8e969e70afea9f324c1ec9f 100644 (file)
@@ -1,34 +1,5 @@
-#ifndef VEHICLE_BUMBLEBEE
-#define VEHICLE_BUMBLEBEE
 #include "bumblebee.qh"
 
-#include "bumblebee_weapons.qh"
-
-CLASS(Bumblebee, Vehicle)
-/* spawnflags */ ATTRIB(Bumblebee, spawnflags, int, VHF_DMGSHAKE);
-/* mins       */ ATTRIB(Bumblebee, mins, vector, '-245 -130 -130');
-/* maxs       */ ATTRIB(Bumblebee, maxs, vector, '230 130 130');
-/* view offset*/ ATTRIB(Bumblebee, view_ofs, vector, '0 0 300');
-/* view dist  */ ATTRIB(Bumblebee, height, float, 450);
-/* model         */ ATTRIB(Bumblebee, mdl, string, "models/vehicles/bumblebee_body.dpm");
-/* model         */ ATTRIB(Bumblebee, model, string, "models/vehicles/bumblebee_body.dpm");
-/* head_model */ ATTRIB(Bumblebee, head_model, string, "");
-/* hud_model  */ ATTRIB(Bumblebee, hud_model, string, "models/vehicles/spiderbot_cockpit.dpm");
-/* tags       */ ATTRIB(Bumblebee, tag_head, string, "");
-/* tags       */ ATTRIB(Bumblebee, tag_hud, string, "");
-/* tags       */ ATTRIB(Bumblebee, tag_view, string, "tag_viewport");
-/* netname    */ ATTRIB(Bumblebee, netname, string, "bumblebee");
-/* fullname   */ ATTRIB(Bumblebee, vehicle_name, string, _("Bumblebee"));
-/* icon       */ ATTRIB(Bumblebee, m_icon, string, "vehicle_bumble");
-ENDCLASS(Bumblebee)
-REGISTER_VEHICLE(BUMBLEBEE, NEW(Bumblebee));
-
-#ifndef MENUQC
-       MODEL(VEH_BUMBLEBEE_GUNCOCKPIT, "models/vehicles/wakizashi_cockpit.dpm");
-#endif
-
-#endif
-
 #ifdef IMPLEMENTATION
 
 const float BRG_SETUP = 2;
index b675185d49454681ed545b493921aceb421735c1..2c90b7c40b9452d610de5e3f02f0a6b91613b0dd 100644 (file)
@@ -1,6 +1,30 @@
 #pragma once
 
-#ifdef CSQC
+#include "bumblebee_weapons.qh"
+
+CLASS(Bumblebee, Vehicle)
+/* spawnflags */ ATTRIB(Bumblebee, spawnflags, int, VHF_DMGSHAKE);
+/* mins       */ ATTRIB(Bumblebee, mins, vector, '-245 -130 -130');
+/* maxs       */ ATTRIB(Bumblebee, maxs, vector, '230 130 130');
+/* view offset*/ ATTRIB(Bumblebee, view_ofs, vector, '0 0 300');
+/* view dist  */ ATTRIB(Bumblebee, height, float, 450);
+/* model         */ ATTRIB(Bumblebee, mdl, string, "models/vehicles/bumblebee_body.dpm");
+/* model         */ ATTRIB(Bumblebee, model, string, "models/vehicles/bumblebee_body.dpm");
+/* head_model */ ATTRIB(Bumblebee, head_model, string, "");
+/* hud_model  */ ATTRIB(Bumblebee, hud_model, string, "models/vehicles/spiderbot_cockpit.dpm");
+/* tags       */ ATTRIB(Bumblebee, tag_head, string, "");
+/* tags       */ ATTRIB(Bumblebee, tag_hud, string, "");
+/* tags       */ ATTRIB(Bumblebee, tag_view, string, "tag_viewport");
+/* netname    */ ATTRIB(Bumblebee, netname, string, "bumblebee");
+/* fullname   */ ATTRIB(Bumblebee, vehicle_name, string, _("Bumblebee"));
+/* icon       */ ATTRIB(Bumblebee, m_icon, string, "vehicle_bumble");
+ENDCLASS(Bumblebee)
+REGISTER_VEHICLE(BUMBLEBEE, NEW(Bumblebee));
 
+#ifdef GAMEQC
+       MODEL(VEH_BUMBLEBEE_GUNCOCKPIT, "models/vehicles/wakizashi_cockpit.dpm");
+#endif
+
+#ifdef CSQC
 void CSQC_BUMBLE_GUN_HUD();
 #endif
index 73fed55e1cfaecd936a1419ea88926052a5460e9..d4ed9505b987646aaff37d154fbae1e34ebf6f47 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 
 float autocvar_g_vehicle_bumblebee_cannon_cost = 2;
 float autocvar_g_vehicle_bumblebee_cannon_damage = 60;
index 2bccec21a041af2b455231b88dac6861bbdd95f0..c8f8cf84eaf33bb697b4963f96aad90c35e06a47 100644 (file)
@@ -1,28 +1,4 @@
-#ifndef VEHICLE_RACER
-#define VEHICLE_RACER
-
-#include "racer_weapon.qh"
-
-CLASS(Racer, Vehicle)
-/* spawnflags */ ATTRIB(Racer, spawnflags, int, VHF_DMGSHAKE | VHF_DMGROLL);
-/* mins       */ ATTRIB(Racer, mins, vector, '-120 -120 -40' * 0.5);
-/* maxs       */ ATTRIB(Racer, maxs, vector, '120 120 40' * 0.5);
-/* view offset*/ ATTRIB(Racer, view_ofs, vector, '0 0 50');
-/* view dist  */ ATTRIB(Racer, height, float, 200);
-/* model         */ ATTRIB(Racer, mdl, string, "models/vehicles/wakizashi.dpm");
-/* model         */ ATTRIB(Racer, model, string, "models/vehicles/wakizashi.dpm");
-/* head_model */ ATTRIB(Racer, head_model, string, "null");
-/* hud_model  */ ATTRIB(Racer, hud_model, string, "models/vehicles/wakizashi_cockpit.dpm");
-/* tags       */ ATTRIB(Racer, tag_head, string, "");
-/* tags       */ ATTRIB(Racer, tag_hud, string, "");
-/* tags       */ ATTRIB(Racer, tag_view, string, "tag_viewport");
-/* netname    */ ATTRIB(Racer, netname, string, "racer");
-/* fullname   */ ATTRIB(Racer, vehicle_name, string, _("Racer"));
-/* icon       */ ATTRIB(Racer, m_icon, string, "vehicle_racer");
-ENDCLASS(Racer)
-REGISTER_VEHICLE(RACER, NEW(Racer));
-
-#endif
+#include "racer.qh"
 
 #ifdef IMPLEMENTATION
 
diff --git a/qcsrc/common/vehicles/vehicle/racer.qh b/qcsrc/common/vehicles/vehicle/racer.qh
new file mode 100644 (file)
index 0000000..dd14144
--- /dev/null
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "racer_weapon.qh"
+
+CLASS(Racer, Vehicle)
+/* spawnflags */ ATTRIB(Racer, spawnflags, int, VHF_DMGSHAKE | VHF_DMGROLL);
+/* mins       */ ATTRIB(Racer, mins, vector, '-120 -120 -40' * 0.5);
+/* maxs       */ ATTRIB(Racer, maxs, vector, '120 120 40' * 0.5);
+/* view offset*/ ATTRIB(Racer, view_ofs, vector, '0 0 50');
+/* view dist  */ ATTRIB(Racer, height, float, 200);
+/* model         */ ATTRIB(Racer, mdl, string, "models/vehicles/wakizashi.dpm");
+/* model         */ ATTRIB(Racer, model, string, "models/vehicles/wakizashi.dpm");
+/* head_model */ ATTRIB(Racer, head_model, string, "null");
+/* hud_model  */ ATTRIB(Racer, hud_model, string, "models/vehicles/wakizashi_cockpit.dpm");
+/* tags       */ ATTRIB(Racer, tag_head, string, "");
+/* tags       */ ATTRIB(Racer, tag_hud, string, "");
+/* tags       */ ATTRIB(Racer, tag_view, string, "tag_viewport");
+/* netname    */ ATTRIB(Racer, netname, string, "racer");
+/* fullname   */ ATTRIB(Racer, vehicle_name, string, _("Racer"));
+/* icon       */ ATTRIB(Racer, m_icon, string, "vehicle_racer");
+ENDCLASS(Racer)
+REGISTER_VEHICLE(RACER, NEW(Racer));
index fc9e352542c3a00c76cc2209241b7247bfec01b5..51c20ef9d0244a4dd994b5ed00e4570d224e0b77 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 
 CLASS(RacerAttack, PortoLaunch)
 /* flags     */ ATTRIB(RacerAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
index 510f63ba1fdb2ff9c7020c5b7daac7e19efb2bdc..a03c936bd787f6d8e075857ed38b3efc8c5841f3 100644 (file)
@@ -1,30 +1,5 @@
-#ifndef VEHICLE_RAPTOR
-#define VEHICLE_RAPTOR
 #include "raptor.qh"
 
-#include "raptor_weapons.qh"
-
-CLASS(Raptor, Vehicle)
-/* spawnflags */ ATTRIB(Raptor, spawnflags, int, VHF_DMGSHAKE | VHF_DMGROLL);
-/* mins       */ ATTRIB(Raptor, mins, vector, '-80 -80 0');
-/* maxs       */ ATTRIB(Raptor, maxs, vector, '80 80 70');
-/* view offset*/ ATTRIB(Raptor, view_ofs, vector, '0 0 160');
-/* view dist  */ ATTRIB(Raptor, height, float, 200);
-/* model         */ ATTRIB(Raptor, mdl, string, "models/vehicles/raptor.dpm");
-/* model         */ ATTRIB(Raptor, model, string, "models/vehicles/raptor.dpm");
-/* head_model */ ATTRIB(Raptor, head_model, string, "");
-/* hud_model  */ ATTRIB(Raptor, hud_model, string, "models/vehicles/raptor_cockpit.dpm");
-/* tags       */ ATTRIB(Raptor, tag_head, string, "");
-/* tags       */ ATTRIB(Raptor, tag_hud, string, "tag_hud");
-/* tags       */ ATTRIB(Raptor, tag_view, string, "tag_camera");
-/* netname    */ ATTRIB(Raptor, netname, string, "raptor");
-/* fullname   */ ATTRIB(Raptor, vehicle_name, string, _("Raptor"));
-/* icon       */ ATTRIB(Raptor, m_icon, string, "vehicle_raptor");
-ENDCLASS(Raptor)
-REGISTER_VEHICLE(RAPTOR, NEW(Raptor));
-
-#endif
-
 #ifdef IMPLEMENTATION
 
 #ifdef SVQC
index fd9a7de790b8f49287d0092eafe1663ec0130da2..12666523c7bf8507a390e27339bce29c808f3352 100644 (file)
@@ -1,5 +1,26 @@
 #pragma once
 
+#include "raptor_weapons.qh"
+
+CLASS(Raptor, Vehicle)
+/* spawnflags */ ATTRIB(Raptor, spawnflags, int, VHF_DMGSHAKE | VHF_DMGROLL);
+/* mins       */ ATTRIB(Raptor, mins, vector, '-80 -80 0');
+/* maxs       */ ATTRIB(Raptor, maxs, vector, '80 80 70');
+/* view offset*/ ATTRIB(Raptor, view_ofs, vector, '0 0 160');
+/* view dist  */ ATTRIB(Raptor, height, float, 200);
+/* model         */ ATTRIB(Raptor, mdl, string, "models/vehicles/raptor.dpm");
+/* model         */ ATTRIB(Raptor, model, string, "models/vehicles/raptor.dpm");
+/* head_model */ ATTRIB(Raptor, head_model, string, "");
+/* hud_model  */ ATTRIB(Raptor, hud_model, string, "models/vehicles/raptor_cockpit.dpm");
+/* tags       */ ATTRIB(Raptor, tag_head, string, "");
+/* tags       */ ATTRIB(Raptor, tag_hud, string, "tag_hud");
+/* tags       */ ATTRIB(Raptor, tag_view, string, "tag_camera");
+/* netname    */ ATTRIB(Raptor, netname, string, "raptor");
+/* fullname   */ ATTRIB(Raptor, vehicle_name, string, _("Raptor"));
+/* icon       */ ATTRIB(Raptor, m_icon, string, "vehicle_raptor");
+ENDCLASS(Raptor)
+REGISTER_VEHICLE(RAPTOR, NEW(Raptor));
+
 const int RSM_FIRST = 1;
 const int RSM_BOMB = 1;
 const int RSM_FLARE = 2;
index 502ef80e2cd88af31f94979549c4b6820cb11d0b..4e16efbcc903df3227c1dc30ae419ef7e4f45731 100644 (file)
@@ -201,9 +201,8 @@ void raptor_flare_damage(entity this, entity inflictor, entity attacker, float d
 void raptor_flare_think(entity this)
 {
     this.nextthink = time + 0.1;
-    FOREACH_ENTITY_ENT(enemy, this.owner,
+    IL_EACH(g_projectiles, it.enemy == this.owner,
     {
-        if(it.flags & FL_PROJECTILE)
         if(vdist(this.origin - it.origin, <, autocvar_g_vehicle_raptor_flare_range))
         if(random() > autocvar_g_vehicle_raptor_flare_chase)
             it.enemy = this;
index 0b3af4169d143dafdf42243d246b1c4e0ddf1e13..4260d4292ee47649ba2b8592756c2be0116e78aa 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 
 CLASS(RaptorCannon, PortoLaunch)
 /* flags     */ ATTRIB(RaptorCannon, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
index 3365266f80fbd33ee9c49683da03e1d590d0a53a..ec06104824e1c555bc7792f0929787344625c1d2 100644 (file)
@@ -1,29 +1,4 @@
-#ifndef VEHICLE_SPIDERBOT
-#define VEHICLE_SPIDERBOT
-
-#include "spiderbot_weapons.qh"
-
-CLASS(Spiderbot, Vehicle)
-/* spawnflags */ ATTRIB(Spiderbot, spawnflags, int, VHF_DMGSHAKE);
-/* mins       */ ATTRIB(Spiderbot, mins, vector, '-75 -75 10');
-/* maxs       */ ATTRIB(Spiderbot, maxs, vector, '75 75 125');
-/* view offset*/ ATTRIB(Spiderbot, view_ofs, vector, '0 0 70');
-/* view dist  */ ATTRIB(Spiderbot, height, float, 170);
-/* model         */ ATTRIB(Spiderbot, mdl, string, "models/vehicles/spiderbot.dpm");
-/* model         */ ATTRIB(Spiderbot, model, string, "models/vehicles/spiderbot.dpm");
-/* head_model */ ATTRIB(Spiderbot, head_model, string, "models/vehicles/spiderbot_top.dpm");
-/* hud_model  */ ATTRIB(Spiderbot, hud_model, string, "models/vehicles/spiderbot_cockpit.dpm");
-/* tags       */ ATTRIB(Spiderbot, tag_head, string, "tag_head");
-/* tags       */ ATTRIB(Spiderbot, tag_hud, string, "tag_hud");
-/* tags       */ ATTRIB(Spiderbot, tag_view, string, "");
-/* netname    */ ATTRIB(Spiderbot, netname, string, "spiderbot");
-/* fullname   */ ATTRIB(Spiderbot, vehicle_name, string, _("Spiderbot"));
-/* icon       */ ATTRIB(Spiderbot, m_icon, string, "vehicle_spider");
-ENDCLASS(Spiderbot)
-
-REGISTER_VEHICLE(SPIDERBOT, NEW(Spiderbot));
-
-#endif
+#include "spiderbot.qh"
 
 #ifdef IMPLEMENTATION
 
@@ -339,9 +314,8 @@ void spiderbot_exit(entity this, int eject)
 {
        vector spot;
 
-       FOREACH_ENTITY_ENT(owner, this.owner,
+       IL_EACH(g_projectiles, it.owner == this.owner && it.classname == "spiderbot_rocket",
        {
-               if(it.classname != "spiderbot_rocket") continue;
                it.realowner = this.owner;
                it.owner = NULL;
        });
diff --git a/qcsrc/common/vehicles/vehicle/spiderbot.qh b/qcsrc/common/vehicles/vehicle/spiderbot.qh
new file mode 100644 (file)
index 0000000..a594ace
--- /dev/null
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "spiderbot_weapons.qh"
+
+CLASS(Spiderbot, Vehicle)
+/* spawnflags */ ATTRIB(Spiderbot, spawnflags, int, VHF_DMGSHAKE);
+/* mins       */ ATTRIB(Spiderbot, mins, vector, '-75 -75 10');
+/* maxs       */ ATTRIB(Spiderbot, maxs, vector, '75 75 125');
+/* view offset*/ ATTRIB(Spiderbot, view_ofs, vector, '0 0 70');
+/* view dist  */ ATTRIB(Spiderbot, height, float, 170);
+/* model         */ ATTRIB(Spiderbot, mdl, string, "models/vehicles/spiderbot.dpm");
+/* model         */ ATTRIB(Spiderbot, model, string, "models/vehicles/spiderbot.dpm");
+/* head_model */ ATTRIB(Spiderbot, head_model, string, "models/vehicles/spiderbot_top.dpm");
+/* hud_model  */ ATTRIB(Spiderbot, hud_model, string, "models/vehicles/spiderbot_cockpit.dpm");
+/* tags       */ ATTRIB(Spiderbot, tag_head, string, "tag_head");
+/* tags       */ ATTRIB(Spiderbot, tag_hud, string, "tag_hud");
+/* tags       */ ATTRIB(Spiderbot, tag_view, string, "");
+/* netname    */ ATTRIB(Spiderbot, netname, string, "spiderbot");
+/* fullname   */ ATTRIB(Spiderbot, vehicle_name, string, _("Spiderbot"));
+/* icon       */ ATTRIB(Spiderbot, m_icon, string, "vehicle_spider");
+ENDCLASS(Spiderbot)
+
+REGISTER_VEHICLE(SPIDERBOT, NEW(Spiderbot));
index dc1f6ba60a29e16190c54d930e285af683b314d0..5f7a2c31c8a928cbbc5efec1d99e869a0c01a6fc 100644 (file)
@@ -48,16 +48,17 @@ void spiderbot_rocket_guided(entity this)
 
 void spiderbot_guide_release(entity this)
 {
-    FOREACH_ENTITY_ENT(realowner, this.owner,
+    bool donetrace = false;
+    IL_EACH(g_projectiles, it.realowner == this.owner && getthink(it) == spiderbot_rocket_guided,
     {
-        if(i == 0) // something exists, let's trace!
-            crosshair_trace(this.owner);
-
-        if(getthink(it) == spiderbot_rocket_guided)
+        if(!donetrace) // something exists, let's trace!
         {
-            it.pos1 = trace_endpos;
-            setthink(it, spiderbot_rocket_unguided);
+            donetrace = true;
+            crosshair_trace(this.owner);
         }
+
+        it.pos1 = trace_endpos;
+        setthink(it, spiderbot_rocket_unguided);
     });
 }
 
index 61e2b02501fc74e14eb6f064304116dde8415936..a1523045a6ca000ee6eab8119fead769288dc31f 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 
 #ifdef SVQC
 void spiderbot_rocket_do(entity this);
diff --git a/qcsrc/common/vehicles/vehicles.qc b/qcsrc/common/vehicles/vehicles.qc
new file mode 100644 (file)
index 0000000..5e77365
--- /dev/null
@@ -0,0 +1 @@
+#include "vehicles.qh"
diff --git a/qcsrc/common/vehicles/vehicles.qh b/qcsrc/common/vehicles/vehicles.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 4b6a6997a4c86a800b5c9a3692d7193a8375ec7e..7d6a3818e0ee8fd5024587e37107569a92db7306 100644 (file)
@@ -1,3 +1,4 @@
+#include "viewloc.qh"
 #include "util.qh"
 
 #if defined(CSQC)
diff --git a/qcsrc/common/weapons/_all.inc b/qcsrc/common/weapons/_all.inc
new file mode 100644 (file)
index 0000000..213c39c
--- /dev/null
@@ -0,0 +1,2 @@
+#include "_all.qh"
+#include "all.qc"
diff --git a/qcsrc/common/weapons/_all.qh b/qcsrc/common/weapons/_all.qh
new file mode 100644 (file)
index 0000000..671dde0
--- /dev/null
@@ -0,0 +1,2 @@
+#pragma once
+#include "all.qh"
index 2b75ec0313f9aa015b916b0d7479c44b12a11be8..cf55aa65214b7a84673da155f3ffb0eece56eb36 100644 (file)
@@ -1,8 +1,7 @@
+#include "all.qh"
 #ifndef WEAPONS_ALL_C
 #define WEAPONS_ALL_C
 
-#include "all.qh"
-
 #if defined(CSQC)
        #include <client/defs.qh>
        #include "../constants.qh"
@@ -19,6 +18,7 @@
        #include <lib/csqcmodel/cl_model.qh>
 #elif defined(MENUQC)
 #elif defined(SVQC)
+       #include <common/items/_mod.qh>
     #include <lib/warpzone/anglestransform.qh>
     #include <lib/warpzone/common.qh>
     #include <lib/warpzone/util_server.qh>
@@ -27,7 +27,7 @@
     #include "../stats.qh"
     #include "../teams.qh"
     #include "../util.qh"
-    #include "../monsters/all.qh"
+    #include "../monsters/_mod.qh"
     #include "config.qh"
     #include <server/weapons/csqcprojectile.qh>
     #include <server/weapons/tracing.qh>
     #include <server/defs.qh>
     #include "../notifications/all.qh"
     #include "../deathtypes/all.qh"
-    #include <server/mutators/all.qh>
+    #include <server/mutators/_mod.qh>
     #include "../mapinfo.qh"
-    #include <server/command/common.qh>
+    #include <server/command/_mod.qh>
     #include <lib/csqcmodel/sv_model.qh>
     #include <server/portals.qh>
     #include <server/g_hook.qh>
 #endif
-#ifndef MENUQC
+#ifdef GAMEQC
        #include "calculations.qc"
 #endif
 #ifdef SVQC
@@ -275,7 +275,7 @@ string W_Model(string w_mdl)
        return M_ARGV(1, string);
 }
 
-#ifndef MENUQC
+#ifdef GAMEQC
 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float algn)
 {
        switch (algn)
@@ -547,7 +547,7 @@ void CL_WeaponEntity_SetModel(entity this, string name, bool _anim)
 }
 #endif
 
-#ifndef MENUQC
+#ifdef GAMEQC
 
 REGISTER_NET_TEMP(wframe)
 #ifdef CSQC
index a3f7eb4d0fa0bb26312e8bc708b2cdf3b9ea90ca..32b03a16be3605d5776bd9d630312cbbb2fac79b 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <common/command/all.qh>
+#include <common/command/_mod.qh>
 #include <common/stats.qh>
 #include "config.qh"
 
@@ -18,7 +18,7 @@ WepSet ReadWepSet();
 
 #include "weapon.qh"
 
-#ifndef MENUQC
+#ifdef GAMEQC
 #include "calculations.qh"
 #include <common/models/all.qh>
 #endif
@@ -322,7 +322,7 @@ STATIC_INIT(register_weapons_done)
     weaponorder_byid = strzone(substring(weaponorder_byid, 1, -1));
 }
 
-#ifndef MENUQC
+#ifdef GAMEQC
 
 .entity weaponchild;
 .entity exteriorweaponentity;
index 73d9b938efac9bdcc4917352b3833665a1dae105..c35b1930c44672995718ab746454da9aabfcd243 100644 (file)
@@ -1,3 +1,5 @@
+#include "calculations.qh"
+
 // =============================
 //  Explosion Force Calculation
 // =============================
index 05eb9d9baf299ff4455f06eabed1adea87294587..c349eeca4f355a3b8b55ee588e65cfaf5471739e 100644 (file)
@@ -3,3 +3,4 @@
 vector damage_explosion_calcpush(vector explosion_f, vector target_v, float speedfactor);
 vector W_CalculateSpread(vector forward, float spread, float spreadfactor, float spreadstyle);
 int W_GetGunAlignment(entity player);
+float explosion_calcpush_getmultiplier(vector explosion_v, vector target_v);
index 26a05d10ac739f4b609a5ce39384be48e9ef86d8..4f6177b478f17bc870366358618c21d44133f3a7 100644 (file)
@@ -1,8 +1,8 @@
+#include "config.qh"
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
     #include "../util.qh"
-    #include "config.qh"
     #include "all.qh"
 #endif
 
index a08be2e61d5391c406668e6f5039146ba4748518..7b2f4b5b7a03b33073ecd0ba3c9d63e08dc1e6ce 100644 (file)
@@ -130,11 +130,11 @@ CLASS(Weapon, Object)
        }
 ENDCLASS(Weapon)
 
-#include <common/items/all.qh>
+#include <common/items/_mod.qh>
 CLASS(WeaponPickup, Pickup)
     ATTRIB(WeaponPickup, m_weapon, Weapon);
     ATTRIB(WeaponPickup, m_name, string);
-#ifndef MENUQC
+#ifdef GAMEQC
     ATTRIB(WeaponPickup, m_sound, Sound, SND_WEAPONPICKUP);
 #endif
 #ifdef SVQC
@@ -146,7 +146,7 @@ CLASS(WeaponPickup, Pickup)
         CONSTRUCT(WeaponPickup);
         this.m_weapon = w;
         this.m_name = w.m_name;
-#ifndef MENUQC
+#ifdef GAMEQC
         this.m_model = w.m_model;
 #endif
 #ifdef SVQC
@@ -175,11 +175,6 @@ ENDCLASS(OffhandWeapon)
 
 const int MAX_SHOT_DISTANCE = 32768;
 
-// weapon pickup ratings for bot logic
-const int BOT_PICKUP_RATING_LOW  =  2500;
-const int BOT_PICKUP_RATING_MID  =  5000;
-const int BOT_PICKUP_RATING_HIGH = 10000;
-
 // weapon flags
 const int WEP_TYPE_OTHER          =  0x00; // not for damaging people
 const int WEP_TYPE_SPLASH         =  0x01; // splash damage
index c0d85831ae730be7dc9c9981d9f8b86150286bc5..a61dc0f031d3e9ed4da12e1be93b8e69c703b9fc 100644 (file)
@@ -1,3 +1,4 @@
+#include "arc.qh"
 #ifndef IMPLEMENTATION
 CLASS(Arc, Weapon)
 /* ammotype  */ ATTRIB(Arc, ammo_field, .int, ammo_cells);
@@ -6,7 +7,7 @@ CLASS(Arc, Weapon)
 /* rating    */ ATTRIB(Arc, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
 /* color     */ ATTRIB(Arc, wpcolor, vector, '1 1 1');
 /* modelname */ ATTRIB(Arc, mdl, string, "arc");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Arc, m_model, Model, MDL_ARC_ITEM);
 #endif
 /* crosshair */ ATTRIB(Arc, w_crosshair, string, "gfx/crosshairhlac");
@@ -74,7 +75,7 @@ ENDCLASS(Arc)
 REGISTER_WEAPON(ARC, arc, NEW(Arc));
 
 
-#ifndef MENUQC
+#ifdef GAMEQC
 const float ARC_MAX_SEGMENTS = 20;
 vector arc_shotorigin[4];
 .vector beam_start;
@@ -281,6 +282,7 @@ void W_Arc_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity)
        missile = new(missile);
        missile.owner = missile.realowner = actor;
        missile.bot_dodge = true;
+       IL_PUSH(g_bot_dodge, missile);
        missile.bot_dodgerating = WEP_CVAR(arc, bolt_damage);
 
        missile.takedamage = DAMAGE_YES;
@@ -690,6 +692,7 @@ void W_Arc_Beam(float burst, entity actor, .entity weaponentity)
        beam.owner = actor;
        set_movetype(beam, MOVETYPE_NONE);
        beam.bot_dodge = true;
+       IL_PUSH(g_bot_dodge, beam);
        beam.bot_dodgerating = WEP_CVAR(arc, beam_damage);
        beam.beam_bursting = burst;
        Net_LinkEntity(beam, false, 0, W_Arc_Beam_Send);
@@ -1397,7 +1400,7 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
        {
                this.beam_type = ReadByte();
 
-               vector beamcolor = ((autocvar_cl_arcbeam_teamcolor) ? colormapPaletteColor(stof(getplayerkeyvalue(this.sv_entnum - 1, "colors")) & 0x0F, true) : '1 1 1');
+               vector beamcolor = ((autocvar_cl_arcbeam_teamcolor) ? colormapPaletteColor(entcs_GetClientColors(this.sv_entnum - 1) & 0x0F, true) : '1 1 1');
                switch(this.beam_type)
                {
                        case ARC_BT_MISS:
diff --git a/qcsrc/common/weapons/weapon/arc.qh b/qcsrc/common/weapons/weapon/arc.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 791b574817cfc1d6c8daa56c17889ac09057f33f..2eb8f00b4179c72cd91727168bbee9f7719c93d4 100644 (file)
@@ -1,3 +1,4 @@
+#include "blaster.qh"
 #ifndef IMPLEMENTATION
 CLASS(Blaster, Weapon)
 /* ammotype  */ //ATTRIB(Blaster, ammo_field, .int, ammo_none);
@@ -6,7 +7,7 @@ CLASS(Blaster, Weapon)
 /* rating    */ ATTRIB(Blaster, bot_pickupbasevalue, float, 0);
 /* color     */ ATTRIB(Blaster, wpcolor, vector, '1 0.5 0.5');
 /* modelname */ ATTRIB(Blaster, mdl, string, "laser");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Blaster, m_model, Model, MDL_BLASTER_ITEM);
 #endif
 /* crosshair */ ATTRIB(Blaster, w_crosshair, string, "gfx/crosshairlaser");
@@ -139,6 +140,7 @@ void W_Blaster_Attack(
        settouch(missile, W_Blaster_Touch);
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
+       IL_PUSH(g_bot_dodge, missile);
        missile.missile_flags = MIF_SPLASH;
        missile.projectiledeathtype = atk_deathtype;
        setthink(missile, W_Blaster_Think);
diff --git a/qcsrc/common/weapons/weapon/blaster.qh b/qcsrc/common/weapons/weapon/blaster.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 8865dbd02f1c253f87c902dfec48922aa4611370..58214bf390feed3d2f41e1ec5ec24c847b02c10f 100644 (file)
@@ -1,3 +1,4 @@
+#include "crylink.qh"
 #ifndef IMPLEMENTATION
 CLASS(Crylink, Weapon)
 /* ammotype  */ ATTRIB(Crylink, ammo_field, .int, ammo_cells);
@@ -6,7 +7,7 @@ CLASS(Crylink, Weapon)
 /* rating    */ ATTRIB(Crylink, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
 /* color     */ ATTRIB(Crylink, wpcolor, vector, '1 0.5 1');
 /* modelname */ ATTRIB(Crylink, mdl, string, "crylink");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Crylink, m_model, Model, MDL_CRYLINK_ITEM);
 #endif
 /* crosshair */ ATTRIB(Crylink, w_crosshair, string, "gfx/crosshaircrylink");
@@ -440,6 +441,7 @@ void W_Crylink_Attack(Weapon thiswep, entity actor, .entity weaponentity)
 
                proj.flags = FL_PROJECTILE;
                IL_PUSH(g_projectiles, proj);
+               IL_PUSH(g_bot_dodge, proj);
                proj.missile_flags = MIF_SPLASH;
 
                CSQCProjectile(proj, true, (proj.cnt ? PROJECTILE_CRYLINK_BOUNCING : PROJECTILE_CRYLINK), true);
@@ -556,6 +558,7 @@ void W_Crylink_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
 
                proj.flags = FL_PROJECTILE;
                IL_PUSH(g_projectiles, proj);
+               IL_PUSH(g_bot_dodge, proj);
         proj.missile_flags = MIF_SPLASH;
 
                CSQCProjectile(proj, true, (proj.cnt ? PROJECTILE_CRYLINK_BOUNCING : PROJECTILE_CRYLINK), true);
diff --git a/qcsrc/common/weapons/weapon/crylink.qh b/qcsrc/common/weapons/weapon/crylink.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index e02a474c2d43e817600595e22ae3725060020db6..1fdb8d6ad6773a78cba7a24b428b15c389193357 100644 (file)
@@ -1,3 +1,4 @@
+#include "devastator.qh"
 #ifndef IMPLEMENTATION
 CLASS(Devastator, Weapon)
 /* ammotype  */ ATTRIB(Devastator, ammo_field, .int, ammo_rockets);
@@ -6,7 +7,7 @@ CLASS(Devastator, Weapon)
 /* rating    */ ATTRIB(Devastator, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
 /* color     */ ATTRIB(Devastator, wpcolor, vector, '1 1 0');
 /* modelname */ ATTRIB(Devastator, mdl, string, "rl");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Devastator, m_model, Model, MDL_DEVASTATOR_ITEM);
 #endif
 /* crosshair */ ATTRIB(Devastator, w_crosshair, string, "gfx/crosshairrocketlauncher");
@@ -399,6 +400,7 @@ void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        missile.cnt = time + WEP_CVAR(devastator, lifetime);
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
+       IL_PUSH(g_bot_dodge, missile);
        missile.missile_flags = MIF_SPLASH;
 
        CSQCProjectile(missile, WEP_CVAR(devastator, guiderate) == 0 && WEP_CVAR(devastator, speedaccel) == 0, PROJECTILE_ROCKET, false); // because of fly sound
@@ -414,35 +416,6 @@ void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        MUTATOR_CALLHOOK(EditProjectile, actor, missile);
 }
 
-#if 0
-METHOD(Devastator, wr_aim, void(entity thiswep, entity actor))
-{
-    entity this = actor;
-    // aim and decide to fire if appropriate
-    PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, WEP_CVAR(devastator, speed), 0, WEP_CVAR(devastator, lifetime), false);
-    if(skill >= 2) // skill 0 and 1 bots won't detonate rockets!
-    {
-        // decide whether to detonate rockets
-        entity missile, targetlist, targ;
-        targetlist = findchainfloat(bot_attack, true);
-        for(missile = NULL; (missile = find(missile, classname, "rocket")); ) if(missile.realowner == actor)
-        {
-            targ = targetlist;
-            while(targ)
-            {
-                if(targ != missile.realowner && vlen(targ.origin - missile.origin) < WEP_CVAR(devastator, radius))
-                {
-                    PHYS_INPUT_BUTTON_ATCK2(actor) = true;
-                    break;
-                }
-                targ = targ.chain;
-            }
-        }
-
-        if(PHYS_INPUT_BUTTON_ATCK2(actor)) PHYS_INPUT_BUTTON_ATCK(actor) = false;
-    }
-}
-#else
 METHOD(Devastator, wr_aim, void(entity thiswep, entity actor))
 {
     // aim and decide to fire if appropriate
@@ -459,12 +432,10 @@ METHOD(Devastator, wr_aim, void(entity thiswep, entity actor))
         selfdamage = 0;
         teamdamage = 0;
         enemydamage = 0;
-        FOREACH_ENTITY_ENT(realowner, actor,
+        IL_EACH(g_projectiles, it.realowner == actor && it.classname == "rocket",
         {
-            if(it.classname != "rocket") continue;
-
             entity rocket = it;
-            FOREACH_ENTITY_FLOAT(bot_attack, true,
+            IL_EACH(g_bot_targets, it.bot_attack,
             {
                float d = vlen(it.origin + (it.mins + it.maxs) * 0.5 - rocket.origin);
                d = bound(0, edgedamage + (coredamage - edgedamage) * sqrt(1 - d * recipricoledgeradius), 10000);
@@ -485,14 +456,12 @@ METHOD(Devastator, wr_aim, void(entity thiswep, entity actor))
             desirabledamage = desirabledamage - teamdamage;
 
         makevectors(actor.v_angle);
-        FOREACH_ENTITY_ENT(realowner, actor,
+        IL_EACH(g_projectiles, it.realowner == actor && it.classname == "rocket",
         {
-            if(it.classname != "rocket") continue;
-
             if(skill > 9) // normal players only do this for the target they are tracking
             {
                    entity rocket = it;
-                   FOREACH_ENTITY_FLOAT(bot_attack, true,
+                   IL_EACH(g_bot_targets, it.bot_attack,
                    {
                        if((v_forward * normalize(rocket.origin - it.origin) < 0.1)
                            && desirabledamage > 0.1 * coredamage
@@ -525,7 +494,7 @@ METHOD(Devastator, wr_aim, void(entity thiswep, entity actor))
         if(PHYS_INPUT_BUTTON_ATCK2(actor)) PHYS_INPUT_BUTTON_ATCK(actor) = false;
     }
 }
-#endif
+
 METHOD(Devastator, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
 {
     if(WEP_CVAR(devastator, reload_ammo) && actor.clip_load < WEP_CVAR(devastator, ammo)) { // forced reload
@@ -548,16 +517,15 @@ METHOD(Devastator, wr_think, void(entity thiswep, entity actor, .entity weaponen
         if(fire & 2)
         if(PS(actor).m_switchweapon == WEP_DEVASTATOR)
         {
-            entity rock;
             bool rockfound = false;
-            for(rock = NULL; (rock = find(rock, classname, "rocket")); ) if(rock.realowner == actor)
+            IL_EACH(g_projectiles, it.realowner == actor && it.classname == "rocket",
             {
-                if(!rock.rl_detonate_later)
+                if(!it.rl_detonate_later)
                 {
-                    rock.rl_detonate_later = true;
+                    it.rl_detonate_later = true;
                     rockfound = true;
                 }
-            }
+            });
             if(rockfound)
                 sound(actor, CH_WEAPON_B, SND_ROCKET_DET, VOL_BASE, ATTN_NORM);
         }
diff --git a/qcsrc/common/weapons/weapon/devastator.qh b/qcsrc/common/weapons/weapon/devastator.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 2c74b3b451477c364232467a1792826c027cf994..7e05241a490873f200bbd1ecbeb5cbd8ec43e0ab 100644 (file)
@@ -1,3 +1,4 @@
+#include "electro.qh"
 #ifndef IMPLEMENTATION
 CLASS(Electro, Weapon)
 /* ammotype  */ ATTRIB(Electro, ammo_field, .int, ammo_cells);
@@ -6,7 +7,7 @@ CLASS(Electro, Weapon)
 /* rating    */ ATTRIB(Electro, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
 /* color     */ ATTRIB(Electro, wpcolor, vector, '0 0.5 1');
 /* modelname */ ATTRIB(Electro, mdl, string, "electro");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Electro, m_model, Model, MDL_ELECTRO_ITEM);
 #endif
 /* crosshair */ ATTRIB(Electro, w_crosshair, string, "gfx/crosshairelectro");
@@ -300,6 +301,7 @@ void W_Electro_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity)
        setsize(proj, '0 0 -3', '0 0 -3');
        proj.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, proj);
+       IL_PUSH(g_bot_dodge, proj);
        proj.missile_flags = MIF_SPLASH;
 
        CSQCProjectile(proj, true, PROJECTILE_ELECTRO_BEAM, true);
@@ -339,6 +341,8 @@ void W_Electro_Orb_Stick(entity this, entity to)
        newproj.nextthink = this.nextthink;
        newproj.use = this.use;
        newproj.flags = this.flags;
+       IL_PUSH(g_projectiles, newproj);
+       IL_PUSH(g_bot_dodge, newproj);
 
        delete(this);
 
@@ -447,6 +451,7 @@ void W_Electro_Attack_Orb(Weapon thiswep, entity actor, .entity weaponentity)
        proj.event_damage = W_Electro_Orb_Damage;
        proj.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, proj);
+       IL_PUSH(g_bot_dodge, proj);
        proj.damagedbycontents = (WEP_CVAR_SEC(electro, damagedbycontents));
 
        proj.bouncefactor = WEP_CVAR_SEC(electro, bouncefactor);
diff --git a/qcsrc/common/weapons/weapon/electro.qh b/qcsrc/common/weapons/weapon/electro.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 8d17a247d4c36c8408473c8c7b595e96c168ca7b..c2b93747c8c4c14d7d9437f6c50e2cc2934b8d89 100644 (file)
@@ -1,3 +1,4 @@
+#include "fireball.qh"
 #ifndef IMPLEMENTATION
 CLASS(Fireball, Weapon)
 /* ammotype  */ //ATTRIB(Fireball, ammo_field, .int, ammo_none);
@@ -6,7 +7,7 @@ CLASS(Fireball, Weapon)
 /* rating    */ ATTRIB(Fireball, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
 /* color     */ ATTRIB(Fireball, wpcolor, vector, '1 0.5 0');
 /* modelname */ ATTRIB(Fireball, mdl, string, "fireball");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Fireball, m_model, Model, MDL_FIREBALL_ITEM);
 #endif
 /* crosshair */ ATTRIB(Fireball, w_crosshair, string, "gfx/crosshairfireball");
@@ -223,6 +224,7 @@ void W_Fireball_Attack1(entity actor, .entity weaponentity)
        setsize(proj, '-16 -16 -16', '16 16 16');
        proj.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, proj);
+       IL_PUSH(g_bot_dodge, proj);
     proj.missile_flags = MIF_SPLASH | MIF_PROXY;
 
        CSQCProjectile(proj, true, PROJECTILE_FIREBALL, true);
@@ -354,6 +356,7 @@ void W_Fireball_Attack2(entity actor, .entity weaponentity)
        proj.angles = vectoangles(proj.velocity);
        proj.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, proj);
+       IL_PUSH(g_bot_dodge, proj);
     proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC;
 
        CSQCProjectile(proj, true, PROJECTILE_FIREMINE, true);
diff --git a/qcsrc/common/weapons/weapon/fireball.qh b/qcsrc/common/weapons/weapon/fireball.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index c83203272d8c935c1408dbeb087a2972b96c9f59..9a178c03bbc0a47dd6fd8af8bdeb8be1ebdd96f4 100644 (file)
@@ -1,3 +1,4 @@
+#include "hagar.qh"
 #ifndef IMPLEMENTATION
 CLASS(Hagar, Weapon)
 /* ammotype  */ ATTRIB(Hagar, ammo_field, .int, ammo_rockets);
@@ -6,7 +7,7 @@ CLASS(Hagar, Weapon)
 /* rating    */ ATTRIB(Hagar, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
 /* color     */ ATTRIB(Hagar, wpcolor, vector, '1 1 0.5');
 /* modelname */ ATTRIB(Hagar, mdl, string, "hagar");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Hagar, m_model, Model, MDL_HAGAR_ITEM);
 #endif
 /* crosshair */ ATTRIB(Hagar, w_crosshair, string, "gfx/crosshairhagar");
@@ -170,6 +171,7 @@ void W_Hagar_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        missile.angles = vectoangles(missile.velocity);
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
+       IL_PUSH(g_bot_dodge, missile);
        missile.missile_flags = MIF_SPLASH;
 
        CSQCProjectile(missile, true, PROJECTILE_HAGAR, true);
@@ -214,6 +216,7 @@ void W_Hagar_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
        missile.angles = vectoangles(missile.velocity);
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
+       IL_PUSH(g_bot_dodge, missile);
        missile.missile_flags = MIF_SPLASH;
 
        CSQCProjectile(missile, true, PROJECTILE_HAGAR_BOUNCING, true);
@@ -291,6 +294,7 @@ void W_Hagar_Attack2_Load_Release(entity actor, .entity weaponentity)
                missile.angles = vectoangles(missile.velocity);
                missile.flags = FL_PROJECTILE;
                IL_PUSH(g_projectiles, missile);
+               IL_PUSH(g_bot_dodge, missile);
 
                CSQCProjectile(missile, true, PROJECTILE_HAGAR, true);
 
diff --git a/qcsrc/common/weapons/weapon/hagar.qh b/qcsrc/common/weapons/weapon/hagar.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index b545f6ce1ea7d4a1cf52d9d8c55d7ce62d6995cd..79bf08193ec05b9b38e3fa1ac1be46ca102043f3 100644 (file)
@@ -1,3 +1,4 @@
+#include "hlac.qh"
 #ifndef IMPLEMENTATION
 CLASS(HLAC, Weapon)
 /* ammotype  */ ATTRIB(HLAC, ammo_field, .int, ammo_cells);
@@ -6,7 +7,7 @@ CLASS(HLAC, Weapon)
 /* rating    */ ATTRIB(HLAC, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
 /* color     */ ATTRIB(HLAC, wpcolor, vector, '0 1 0');
 /* modelname */ ATTRIB(HLAC, mdl, string, "hlac");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(HLAC, m_model, Model, MDL_HLAC_ITEM);
 #endif
 /* crosshair */ ATTRIB(HLAC, w_crosshair, string, "gfx/crosshairhlac");
@@ -111,6 +112,7 @@ void W_HLAC_Attack(Weapon thiswep, entity actor, .entity weaponentity)
 
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
+       IL_PUSH(g_bot_dodge, missile);
        missile.projectiledeathtype = WEP_HLAC.m_id;
 
        CSQCProjectile(missile, true, PROJECTILE_HLAC, true);
@@ -154,6 +156,7 @@ void W_HLAC_Attack2(entity actor, .entity weaponentity)
 
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
+       IL_PUSH(g_bot_dodge, missile);
        missile.missile_flags = MIF_SPLASH;
        missile.projectiledeathtype = WEP_HLAC.m_id | HITTYPE_SECONDARY;
 
diff --git a/qcsrc/common/weapons/weapon/hlac.qh b/qcsrc/common/weapons/weapon/hlac.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 5e8119e6a6a5bc74d2497fb019b9ac129d9c604f..23e7c23ae5b2b16ccdd9b918e03ea378cfef60e4 100644 (file)
@@ -1,3 +1,4 @@
+#include "hook.qh"
 #ifndef IMPLEMENTATION
 CLASS(Hook, Weapon)
 /* ammotype  */ ATTRIB(Hook, ammo_field, .int, ammo_fuel);
@@ -6,7 +7,7 @@ CLASS(Hook, Weapon)
 /* rating    */ ATTRIB(Hook, bot_pickupbasevalue, float, 0);
 /* color     */ ATTRIB(Hook, wpcolor, vector, '0 0.5 0');
 /* modelname */ ATTRIB(Hook, mdl, string, "hookgun");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Hook, m_model, Model, MDL_HOOK_ITEM);
 #endif
 /* crosshair */ ATTRIB(Hook, w_crosshair, string, "gfx/crosshairhook");
@@ -180,6 +181,7 @@ void W_Hook_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
        gren.angles = '0 0 0';
        gren.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, gren);
+       IL_PUSH(g_bot_dodge, gren);
 
        CSQCProjectile(gren, true, PROJECTILE_HOOKBOMB, true);
 
diff --git a/qcsrc/common/weapons/weapon/hook.qh b/qcsrc/common/weapons/weapon/hook.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index e3d1da2fea86db9d6ad4cff51cbe881a45e5273e..81da28ddb05b3741fa0d68f180829f8b49380130 100644 (file)
@@ -1,3 +1,4 @@
+#include "machinegun.qh"
 #ifndef IMPLEMENTATION
 CLASS(MachineGun, Weapon)
 /* ammotype  */ ATTRIB(MachineGun, ammo_field, .int, ammo_nails);
@@ -6,7 +7,7 @@ CLASS(MachineGun, Weapon)
 /* rating    */ ATTRIB(MachineGun, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
 /* color     */ ATTRIB(MachineGun, wpcolor, vector, '1 1 0');
 /* modelname */ ATTRIB(MachineGun, mdl, string, "uzi");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(MachineGun, m_model, Model, MDL_MACHINEGUN_ITEM);
 #endif
 /* crosshair */ ATTRIB(MachineGun, w_crosshair, string, "gfx/crosshairuzi");
diff --git a/qcsrc/common/weapons/weapon/machinegun.qh b/qcsrc/common/weapons/weapon/machinegun.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 3021f47454500838ebcdded983139fdeaea55f85..5f5898aa41b78953872242278cfb5e3067a1cf54 100644 (file)
@@ -1,3 +1,4 @@
+#include "minelayer.qh"
 #ifndef IMPLEMENTATION
 CLASS(MineLayer, Weapon)
 /* ammotype  */ ATTRIB(MineLayer, ammo_field, .int, ammo_rockets);
@@ -6,7 +7,7 @@ CLASS(MineLayer, Weapon)
 /* rating    */ ATTRIB(MineLayer, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
 /* color     */ ATTRIB(MineLayer, wpcolor, vector, '0.75 1 0');
 /* modelname */ ATTRIB(MineLayer, mdl, string, "minelayer");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(MineLayer, m_model, Model, MDL_MINELAYER_ITEM);
 #endif
 /* crosshair */ ATTRIB(MineLayer, w_crosshair, string, "gfx/crosshairminelayer");
@@ -103,6 +104,7 @@ void W_MineLayer_Stick(entity this, entity to)
        newmine.cnt = this.cnt;
        newmine.flags = this.flags;
        IL_PUSH(g_projectiles, newmine);
+       IL_PUSH(g_bot_dodge, newmine);
 
        delete(this);
 
@@ -372,6 +374,7 @@ void W_MineLayer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        mine.cnt = (WEP_CVAR(minelayer, lifetime) - WEP_CVAR(minelayer, lifetime_countdown));
        mine.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, mine);
+       IL_PUSH(g_bot_dodge, mine);
        mine.missile_flags = MIF_SPLASH | MIF_ARC | MIF_PROXY;
 
        if(mine.cnt > 0) { mine.cnt += time; }
@@ -435,7 +438,7 @@ METHOD(MineLayer, wr_aim, void(entity thiswep, entity actor))
         IL_EACH(g_mines, it.realowner == actor,
         {
                entity mine = it;
-               FOREACH_ENTITY_FLOAT(bot_attack, true,
+               IL_EACH(g_bot_targets, it.bot_attack,
                {
                        float d = vlen(it.origin + (it.mins + it.maxs) * 0.5 - mine.origin);
                        d = bound(0, edgedamage + (coredamage - edgedamage) * sqrt(1 - d * recipricoledgeradius), 10000);
@@ -462,7 +465,7 @@ METHOD(MineLayer, wr_aim, void(entity thiswep, entity actor))
             if(skill > 9) // normal players only do this for the target they are tracking
             {
                    entity mine = it;
-                   FOREACH_ENTITY_FLOAT(bot_attack, true,
+                   IL_EACH(g_bot_targets, it.bot_attack,
                    {
                        if((v_forward * normalize(mine.origin - it.origin) < 0.1)
                            && desirabledamage > 0.1 * coredamage
diff --git a/qcsrc/common/weapons/weapon/minelayer.qh b/qcsrc/common/weapons/weapon/minelayer.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 0a457f1a6be1730bfdef5642c529097d9cf16901..1428cc4fa9d8395b74522f6fc69f2e616d3f90ea 100644 (file)
@@ -1,3 +1,4 @@
+#include "mortar.qh"
 #ifndef IMPLEMENTATION
 CLASS(Mortar, Weapon)
 /* ammotype  */ ATTRIB(Mortar, ammo_field, .int, ammo_rockets);
@@ -6,7 +7,7 @@ CLASS(Mortar, Weapon)
 /* rating    */ ATTRIB(Mortar, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
 /* color     */ ATTRIB(Mortar, wpcolor, vector, '1 0 0');
 /* modelname */ ATTRIB(Mortar, mdl, string, "gl");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Mortar, m_model, Model, MDL_MORTAR_ITEM);
 #endif
 /* crosshair */ ATTRIB(Mortar, w_crosshair, string, "gfx/crosshairgrenadelauncher");
@@ -247,6 +248,7 @@ void W_Mortar_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        gren.angles = vectoangles(gren.velocity);
        gren.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, gren);
+       IL_PUSH(g_bot_dodge, gren);
 
        if(WEP_CVAR_PRI(mortar, type) == 0 || WEP_CVAR_PRI(mortar, type) == 2)
                CSQCProjectile(gren, true, PROJECTILE_GRENADE, true);
@@ -295,6 +297,7 @@ void W_Mortar_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
        gren.angles = vectoangles(gren.velocity);
        gren.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, gren);
+       IL_PUSH(g_bot_dodge, gren);
 
        if(WEP_CVAR_SEC(mortar, type) == 0 || WEP_CVAR_SEC(mortar, type) == 2)
                CSQCProjectile(gren, true, PROJECTILE_GRENADE, true);
@@ -360,15 +363,14 @@ METHOD(Mortar, wr_think, void(entity thiswep, entity actor, .entity weaponentity
         if(WEP_CVAR_SEC(mortar, remote_detonateprimary))
         {
             bool nadefound = false;
-            entity nade;
-            for(nade = NULL; (nade = find(nade, classname, "grenade")); ) if(nade.realowner == actor)
+            IL_EACH(g_projectiles, it.realowner == actor && it.classname == "grenade",
             {
-                if(!nade.gl_detonate_later)
+                if(!it.gl_detonate_later)
                 {
-                    nade.gl_detonate_later = true;
+                    it.gl_detonate_later = true;
                     nadefound = true;
                 }
-            }
+            });
             if(nadefound)
                 sound(actor, CH_WEAPON_B, SND_ROCKET_DET, VOL_BASE, ATTN_NORM);
         }
diff --git a/qcsrc/common/weapons/weapon/mortar.qh b/qcsrc/common/weapons/weapon/mortar.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index b5bc00353e025e75f765023654ab13266ff55e5b..3e4654fcbbcc41171454192188a8e1ef9f72f393 100644 (file)
@@ -1,3 +1,4 @@
+#include "porto.qh"
 #ifndef IMPLEMENTATION
 CLASS(PortoLaunch, Weapon)
 /* ammotype  */ ATTRIB(PortoLaunch, ammo_field, .int, ammo_none);
@@ -6,7 +7,7 @@ CLASS(PortoLaunch, Weapon)
 /* rating    */ ATTRIB(PortoLaunch, bot_pickupbasevalue, float, 0);
 /* color     */ ATTRIB(PortoLaunch, wpcolor, vector, '0.5 0.5 0.5');
 /* modelname */ ATTRIB(PortoLaunch, mdl, string, "porto");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(PortoLaunch, m_model, Model, MDL_PORTO_ITEM);
 #endif
 /* crosshair */ ATTRIB(PortoLaunch, w_crosshair, string, "gfx/crosshairporto");
@@ -89,6 +90,7 @@ void W_Porto_Fail(entity this, float failhard)
                if(move_out_of_solid(this))
                {
                        this.flags = FL_ITEM;
+                       IL_PUSH(g_items, this);
                        this.velocity = trigger_push_calculatevelocity(this.origin, this.realowner, 128);
                        tracetoss(this, this);
                        if(vdist(trace_endpos - this.realowner.origin, <, 128))
@@ -276,6 +278,7 @@ void W_Porto_Attack(entity actor, .entity weaponentity, float type)
        gren.angles = vectoangles(gren.velocity);
        gren.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, gren);
+       IL_PUSH(g_bot_dodge, gren);
 
        gren.portal_id = time;
        actor.porto_current = gren;
diff --git a/qcsrc/common/weapons/weapon/porto.qh b/qcsrc/common/weapons/weapon/porto.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 1b6faee7860ca6a4f0296ae7481af98db06ae3a7..478a3152536945aedae9ccbd9a53c369e52b8065 100644 (file)
@@ -1,3 +1,4 @@
+#include "rifle.qh"
 #ifndef IMPLEMENTATION
 CLASS(Rifle, Weapon)
 /* ammotype  */ ATTRIB(Rifle, ammo_field, .int, ammo_nails);
@@ -6,7 +7,7 @@ CLASS(Rifle, Weapon)
 /* rating    */ ATTRIB(Rifle, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
 /* color     */ ATTRIB(Rifle, wpcolor, vector, '0.5 1 0');
 /* modelname */ ATTRIB(Rifle, mdl, string, "campingrifle");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Rifle, m_model, Model, MDL_RIFLE_ITEM);
 #endif
 /* crosshair */ ATTRIB(Rifle, w_crosshair, string, "gfx/crosshairrifle");
diff --git a/qcsrc/common/weapons/weapon/rifle.qh b/qcsrc/common/weapons/weapon/rifle.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 9f0a326ff2d53da99691044fb3bd42f273ed3430..268e1916edc91d0c9e3468c229946ff6ad7ff166 100644 (file)
@@ -1,3 +1,4 @@
+#include "seeker.qh"
 #ifndef IMPLEMENTATION
 CLASS(Seeker, Weapon)
 /* ammotype  */ ATTRIB(Seeker, ammo_field, .int, ammo_rockets);
@@ -6,7 +7,7 @@ CLASS(Seeker, Weapon)
 /* rating    */ ATTRIB(Seeker, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
 /* color     */ ATTRIB(Seeker, wpcolor, vector, '0.5 1 0');
 /* modelname */ ATTRIB(Seeker, mdl, string, "seeker");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Seeker, m_model, Model, MDL_SEEKER_ITEM);
 #endif
 /* crosshair */ ATTRIB(Seeker, w_crosshair, string, "gfx/crosshairseeker");
@@ -294,6 +295,7 @@ void W_Seeker_Fire_Missile(Weapon thiswep, entity actor, .entity weaponentity, v
        set_movetype(missile, MOVETYPE_FLYMISSILE);
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
+       IL_PUSH(g_bot_dodge, missile);
        missile.missile_flags = MIF_SPLASH | MIF_GUIDED_TAG;
 
        W_SetupProjVelocity_UP_PRE(missile, seeker, missile_);
@@ -371,6 +373,7 @@ void W_Seeker_Fire_Flac(Weapon thiswep, entity actor, .entity weaponentity)
        missile.projectiledeathtype = WEP_SEEKER.m_id | HITTYPE_SECONDARY;
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
+       IL_PUSH(g_bot_dodge, missile);
        missile.missile_flags       = MIF_SPLASH;
 
        // csqc projectiles
@@ -593,6 +596,7 @@ void W_Seeker_Fire_Tag(Weapon thiswep, entity actor, .entity weaponentity)
 
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
+       IL_PUSH(g_bot_dodge, missile);
        //missile.missile_flags = MIF_..?;
 
        set_movetype(missile, MOVETYPE_FLY);
diff --git a/qcsrc/common/weapons/weapon/seeker.qh b/qcsrc/common/weapons/weapon/seeker.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index de7726f24f225b1d22d9586bf4b695d92bfa6093..28cbe69bbe5a1a04a7a52f400127070ff5d49732 100644 (file)
@@ -1,3 +1,4 @@
+#include "shockwave.qh"
 #ifndef IMPLEMENTATION
 CLASS(Shockwave, Weapon)
 /* ammotype  */ //ATTRIB(Shockwave, ammo_field, .int, ammo_none);
@@ -6,7 +7,7 @@ CLASS(Shockwave, Weapon)
 /* rating    */ ATTRIB(Shockwave, bot_pickupbasevalue, float, BOT_PICKUP_RATING_LOW);
 /* color     */ ATTRIB(Shockwave, wpcolor, vector, '0.5 0.25 0');
 /* modelname */ ATTRIB(Shockwave, mdl, string, "shotgun");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Shockwave, m_model, Model, MDL_SHOCKWAVE_ITEM);
 #endif
 /* crosshair */ ATTRIB(Shockwave, w_crosshair, string, "gfx/crosshairshotgun");
diff --git a/qcsrc/common/weapons/weapon/shockwave.qh b/qcsrc/common/weapons/weapon/shockwave.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 9c7aff3acab2af395a02bbb10313b025628d6ec3..9ae0c6069ab7b748b8f63a8c4c147891533ec8cf 100644 (file)
@@ -1,3 +1,4 @@
+#include "shotgun.qh"
 #ifndef IMPLEMENTATION
 CLASS(Shotgun, Weapon)
 /* ammotype  */ ATTRIB(Shotgun, ammo_field, .int, ammo_shells);
@@ -6,7 +7,7 @@ CLASS(Shotgun, Weapon)
 /* rating    */ ATTRIB(Shotgun, bot_pickupbasevalue, float, BOT_PICKUP_RATING_LOW);
 /* color     */ ATTRIB(Shotgun, wpcolor, vector, '0.5 0.25 0');
 /* modelname */ ATTRIB(Shotgun, mdl, string, "shotgun");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Shotgun, m_model, Model, MDL_SHOTGUN_ITEM);
 #endif
 /* crosshair */ ATTRIB(Shotgun, w_crosshair, string, "gfx/crosshairshotgun");
diff --git a/qcsrc/common/weapons/weapon/shotgun.qh b/qcsrc/common/weapons/weapon/shotgun.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 31d2bf7a6299fcf735df432d93fa931ee31caf0d..546e59f2410099f36f94129c8e2e51fca53409a1 100644 (file)
@@ -1,3 +1,4 @@
+#include "tuba.qh"
 #ifndef IMPLEMENTATION
 CLASS(Tuba, Weapon)
 /* impulse   */ ATTRIB(Tuba, impulse, int, 1);
@@ -5,7 +6,7 @@ CLASS(Tuba, Weapon)
 /* rating    */ ATTRIB(Tuba, bot_pickupbasevalue, float, BOT_PICKUP_RATING_MID);
 /* color     */ ATTRIB(Tuba, wpcolor, vector, '0 1 0');
 /* modelname */ ATTRIB(Tuba, mdl, string, "tuba");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Tuba, m_model, Model, MDL_TUBA_ITEM);
 #endif
 /* crosshair */ ATTRIB(Tuba, w_crosshair, string, "gfx/crosshairtuba");
diff --git a/qcsrc/common/weapons/weapon/tuba.qh b/qcsrc/common/weapons/weapon/tuba.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 8fa43c1d8c019e73f209a081a778f9c7950b0687..e11e4d8d5211aacc6e6d6e483afd0fe0ac45ea88 100644 (file)
@@ -1,3 +1,4 @@
+#include "vaporizer.qh"
 #ifndef IMPLEMENTATION
 CLASS(Vaporizer, Weapon)
 /* ammotype  */ ATTRIB(Vaporizer, ammo_field, .int, ammo_cells);
@@ -6,7 +7,7 @@ CLASS(Vaporizer, Weapon)
 /* rating    */ ATTRIB(Vaporizer, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
 /* color     */ ATTRIB(Vaporizer, wpcolor, vector, '0.5 1 1');
 /* modelname */ ATTRIB(Vaporizer, mdl, string, "minstanex");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Vaporizer, m_model, Model, MDL_VAPORIZER_ITEM);
 #endif
 /* crosshair */ ATTRIB(Vaporizer, w_crosshair, string, "gfx/crosshairminstanex");
@@ -111,7 +112,7 @@ void VaporizerBeam_Draw(entity this)
        //entity e = CSQCModel_server2csqc(this.sv_entnum - 1);
        //if (e == NULL)
        //{
-               rgb = colormapPaletteColor(stof(getplayerkeyvalue(this.sv_entnum - 1, "colors")) & 0x0F, true);
+               rgb = colormapPaletteColor(entcs_GetClientColors(this.sv_entnum - 1) & 0x0F, true);
                //rgb = '1 1 1';
        //}
        //else
@@ -288,6 +289,7 @@ void W_RocketMinsta_Attack2(entity actor, .entity weaponentity)
         setsize(proj, '0 0 -3', '0 0 -3');
         proj.flags = FL_PROJECTILE;
         IL_PUSH(g_projectiles, proj);
+        IL_PUSH(g_bot_dodge, proj);
         proj.missile_flags = MIF_SPLASH;
 
         CSQCProjectile(proj, true, PROJECTILE_ROCKETMINSTA_LASER, true);
@@ -339,6 +341,7 @@ void W_RocketMinsta_Attack3 (entity actor, .entity weaponentity)
         setsize(proj, '0 0 -3', '0 0 -3');
         proj.flags = FL_PROJECTILE;
         IL_PUSH(g_projectiles, proj);
+        IL_PUSH(g_bot_dodge, proj);
         proj.missile_flags = MIF_SPLASH;
 
         CSQCProjectile(proj, true, PROJECTILE_ROCKETMINSTA_LASER, true);
diff --git a/qcsrc/common/weapons/weapon/vaporizer.qh b/qcsrc/common/weapons/weapon/vaporizer.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 0ca635b3ee32f1e21b8d996117c19bac39858ab8..3e2c1a094e7795dd7e3f99b84ad18a7cd683cece 100644 (file)
@@ -1,3 +1,4 @@
+#include "vortex.qh"
 #ifndef IMPLEMENTATION
 CLASS(Vortex, Weapon)
 /* ammotype  */ ATTRIB(Vortex, ammo_field, .int, ammo_cells);
@@ -6,7 +7,7 @@ CLASS(Vortex, Weapon)
 /* rating    */ ATTRIB(Vortex, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
 /* color     */ ATTRIB(Vortex, wpcolor, vector, '0.5 1 1');
 /* modelname */ ATTRIB(Vortex, mdl, string, "nex");
-#ifndef MENUQC
+#ifdef GAMEQC
 /* model     */ ATTRIB(Vortex, m_model, Model, MDL_VORTEX_ITEM);
 #endif
 /* crosshair */ ATTRIB(Vortex, w_crosshair, string, "gfx/crosshairnex");
diff --git a/qcsrc/common/weapons/weapon/vortex.qh b/qcsrc/common/weapons/weapon/vortex.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 9419dceea18aafb7f8e75f1063b0ab8a3d79c523..16fd93450332e44fa0952d7003f6c50fb1fc6b03 100644 (file)
@@ -8,6 +8,7 @@
 #undef objerror
 #undef remove
 #undef walkmove
+#undef setcolor
 
 #ifdef MENUQC
        #define NULL (0, null_entity)
index 801b8731bc89bf08bdcf8d5ed52c445763986c3e..63cebbc1acd6e0cd74ece6de92ad524cbac82f1e 100644 (file)
@@ -8,3 +8,4 @@
 #define objerror builtin_objerror
 #define remove builtin_remove
 #define walkmove builtin_walkmove
+#define setcolor builtin_setcolor
diff --git a/qcsrc/ecs/_lib.inc b/qcsrc/ecs/_lib.inc
deleted file mode 100644 (file)
index 726f693..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "_lib.qh"
-
-#include "_mod.inc"
-#include "components/_mod.inc"
-#include "events/_mod.inc"
-#include "systems/_mod.inc"
diff --git a/qcsrc/ecs/_lib.qh b/qcsrc/ecs/_lib.qh
deleted file mode 100644 (file)
index a617c73..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#pragma once
-
-/** Components always interpolate from the previous state */
-#define COMPONENT(com) \
-       void com_##com##_interpolate(entity it, float a); \
-       .bool com_##com
-
-#define FOREACH_COMPONENT(com, body) FOREACH_ENTITY_FLOAT(com_##com, true, body)
-
-
-#define EVENT(T, args) .bool evt_##T##_listener; .void args evt_##T
-
-#define emit(T, ...) \
-       MACRO_BEGIN \
-       FOREACH_ENTITY_FLOAT_ORDERED(evt_##T##_listener, true, it.evt_##T(__VA_ARGS__)); \
-       MACRO_END
-
-#define subscribe(listener, T, fn) \
-       MACRO_BEGIN \
-       listener.evt_##T = (fn); \
-       listener.evt_##T##_listener = true; \
-       MACRO_END
-
-
-/**
- * framelimit 0 is no limit, interpolation does not apply
- * framerate below minfps will result in less than 100% speed
- */
-#define SYSTEM(sys, frameLimit, minfps) \
-       void sys_##sys##_update(entity this, float dt); \
-       float autocvar_xon_sys_##sys##_dt = ((frameLimit) ? (1 / (frameLimit)) : 0); \
-       float autocvar_xon_sys_##sys##_minfps = (1 / (1 / (minfps)))
-
-#define SYSTEM_UPDATE(sys) \
-       MACRO_BEGIN \
-       static float t = 0; \
-       float dt = autocvar_xon_sys_##sys##_dt; \
-       float minfps = autocvar_xon_sys_##sys##_minfps; \
-       static float accumulator = 0; \
-       float a = 0; \
-       if (dt) { \
-               accumulator += min(frametime, 1 / (minfps)); \
-       } else { \
-               accumulator += frametime; \
-               dt = accumulator; \
-               a = 1; \
-       } \
-       while (accumulator >= dt) \
-       { \
-               time = t; \
-               FOREACH_COMPONENT(sys, sys_##sys##_update(it, dt)); \
-               t += dt; \
-               accumulator -= dt; \
-       } \
-       if (!a) a = accumulator / dt; \
-       FOREACH_COMPONENT(sys, com_##sys##_interpolate(it, a)); \
-       MACRO_END
index 683c3a91d51b62387b58e61b442e5aa4b8cbef7c..48b7069b243578bea80576dc3d4a3c7715c12e6e 100644 (file)
@@ -1,2 +1,6 @@
 // generated file; do not modify
 #include <ecs/main.qc>
+
+#include <ecs/components/_mod.inc>
+#include <ecs/events/_mod.inc>
+#include <ecs/systems/_mod.inc>
index 4d8bc34da3725bdfce12326f8f29b3d47be62c90..0d1ff4482fc08063cbcbeaab8920cb3aa5246ccb 100644 (file)
@@ -1,2 +1,6 @@
 // generated file; do not modify
 #include <ecs/main.qh>
+
+#include <ecs/components/_mod.qh>
+#include <ecs/events/_mod.qh>
+#include <ecs/systems/_mod.qh>
diff --git a/qcsrc/ecs/lib.qh b/qcsrc/ecs/lib.qh
new file mode 100644 (file)
index 0000000..a617c73
--- /dev/null
@@ -0,0 +1,57 @@
+#pragma once
+
+/** Components always interpolate from the previous state */
+#define COMPONENT(com) \
+       void com_##com##_interpolate(entity it, float a); \
+       .bool com_##com
+
+#define FOREACH_COMPONENT(com, body) FOREACH_ENTITY_FLOAT(com_##com, true, body)
+
+
+#define EVENT(T, args) .bool evt_##T##_listener; .void args evt_##T
+
+#define emit(T, ...) \
+       MACRO_BEGIN \
+       FOREACH_ENTITY_FLOAT_ORDERED(evt_##T##_listener, true, it.evt_##T(__VA_ARGS__)); \
+       MACRO_END
+
+#define subscribe(listener, T, fn) \
+       MACRO_BEGIN \
+       listener.evt_##T = (fn); \
+       listener.evt_##T##_listener = true; \
+       MACRO_END
+
+
+/**
+ * framelimit 0 is no limit, interpolation does not apply
+ * framerate below minfps will result in less than 100% speed
+ */
+#define SYSTEM(sys, frameLimit, minfps) \
+       void sys_##sys##_update(entity this, float dt); \
+       float autocvar_xon_sys_##sys##_dt = ((frameLimit) ? (1 / (frameLimit)) : 0); \
+       float autocvar_xon_sys_##sys##_minfps = (1 / (1 / (minfps)))
+
+#define SYSTEM_UPDATE(sys) \
+       MACRO_BEGIN \
+       static float t = 0; \
+       float dt = autocvar_xon_sys_##sys##_dt; \
+       float minfps = autocvar_xon_sys_##sys##_minfps; \
+       static float accumulator = 0; \
+       float a = 0; \
+       if (dt) { \
+               accumulator += min(frametime, 1 / (minfps)); \
+       } else { \
+               accumulator += frametime; \
+               dt = accumulator; \
+               a = 1; \
+       } \
+       while (accumulator >= dt) \
+       { \
+               time = t; \
+               FOREACH_COMPONENT(sys, sys_##sys##_update(it, dt)); \
+               t += dt; \
+               accumulator -= dt; \
+       } \
+       if (!a) a = accumulator / dt; \
+       FOREACH_COMPONENT(sys, com_##sys##_interpolate(it, a)); \
+       MACRO_END
index 9b7bf3523810b7754d0c302682a6d912edb1968f..724cb1ef8963bf8eb7ddeb447a1f0e5bbf15af53 100644 (file)
@@ -1,3 +1,5 @@
 #pragma once
 
+#include "lib.qh"
+
 void systems_update();
index 83a0ebf34a01bb06755ba9021eeb0e2508340285..b6c3c9e01bea752c9d87f3d66685f3b9d596fedf 100644 (file)
@@ -266,7 +266,6 @@ void make_safe_for_remove(entity this);
 #endif
 #undef ENGINE_EVENT
 
-#ifndef MENUQC
-       #include <ecs/_lib.qh>
-       #include <ecs/components/_mod.qh>
+#ifdef GAMEQC
+       #include <ecs/_mod.qh>
 #endif
diff --git a/qcsrc/lib/angle.qh b/qcsrc/lib/angle.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index a2012c8fa2eea8f14c2b223b2b3fb95f834457d9..cd9569e501008be7c8f1947edf944365fd8f8ddb 100644 (file)
@@ -1,5 +1,13 @@
 // generated file; do not modify
-#include <lib/csqcmodel/cl_model.qc>
-#include <lib/csqcmodel/cl_player.qc>
 #include <lib/csqcmodel/interpolate.qc>
-#include <lib/csqcmodel/sv_model.qc>
+#include <lib/csqcmodel/model.qc>
+#ifdef CSQC
+    #include <lib/csqcmodel/cl_model.qc>
+#endif
+#ifdef SVQC
+    #include <lib/csqcmodel/sv_model.qc>
+#endif
+#include <lib/csqcmodel/player.qc>
+#ifdef CSQC
+    #include <lib/csqcmodel/cl_player.qc>
+#endif
index de3102fa855386521886d9fdb7dad640260fabd4..1b05351928a8cc8c8b06337093a286fa4157ed21 100644 (file)
@@ -1,5 +1,13 @@
 // generated file; do not modify
-#include <lib/csqcmodel/cl_model.qh>
-#include <lib/csqcmodel/cl_player.qh>
 #include <lib/csqcmodel/interpolate.qh>
-#include <lib/csqcmodel/sv_model.qh>
+#include <lib/csqcmodel/model.qh>
+#ifdef CSQC
+    #include <lib/csqcmodel/cl_model.qh>
+#endif
+#ifdef SVQC
+    #include <lib/csqcmodel/sv_model.qh>
+#endif
+#include <lib/csqcmodel/player.qh>
+#ifdef CSQC
+    #include <lib/csqcmodel/cl_player.qh>
+#endif
diff --git a/qcsrc/lib/csqcmodel/model.qc b/qcsrc/lib/csqcmodel/model.qc
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/qcsrc/lib/csqcmodel/model.qh b/qcsrc/lib/csqcmodel/model.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/lib/csqcmodel/player.qc b/qcsrc/lib/csqcmodel/player.qc
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/qcsrc/lib/csqcmodel/player.qh b/qcsrc/lib/csqcmodel/player.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index c20c53440785ceb09f8b236f6bfeef606794b6b2..4f34bb4853ade7f0149274ebdb3c325d4468147a 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#ifndef MENUQC
+#ifdef GAMEQC
 
        #include "oo.qh"
        #include "self.qh"
index 2927a62fe667f9f65484186e7ac9b47c5163f62a..9d3ec54c8e76c1f395ccd83b4ea2cfb585e5d7a7 100644 (file)
@@ -147,7 +147,7 @@ void IL_REMOVE(IntrusiveList this, entity it)
 /**
  * Delete the list
  */
-#define IL_DELETE(this, dtor) \
+#define IL_DELETE(this) \
        MACRO_BEGIN \
        { \
                delete(this); \
index 7183e90feab6bad7a26ce4ba98f8e01886ea8bca..e3cf7410fba38b7177f6d6ee6c928c5f9e7ce122 100644 (file)
@@ -159,7 +159,7 @@ MACRO_END
 .entity _FOREACH_ENTITY_FIND_flags_next; noref string _FOREACH_ENTITY_FIND_flags_mutex;
 #define FOREACH_ENTITY_FLAGS_UNORDERED(fld, match, body) _FOREACH_ENTITY_FIND_UNORDERED(, flags, fld, match, true, body)
 
-#ifndef MENUQC
+#ifdef GAMEQC
 entity(vector org, float rad, .entity tofield) _findchainradius_tofield = #22;
 #define FOREACH_ENTITY_RADIUS(org, dist, cond, body) ORDERED(FOREACH_ENTITY_RADIUS)(org, dist, cond, body)
 .entity _FOREACH_ENTITY_FIND_radius_next; noref string _FOREACH_ENTITY_FIND_radius_mutex;
diff --git a/qcsrc/lib/json.qh b/qcsrc/lib/json.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 27c7ec959c50e79fcafceccaf24732fee6119253..449aa373b31885d5aa3a5958d7855c94c4fd3d6c 100644 (file)
@@ -1,6 +1,6 @@
 #include "command.qh"
 
-#include <common/command/all.qh>
+#include <common/command/_mod.qh>
 
 GENERIC_COMMAND(mx, "Send a matrix command") {
     switch (argv(1)) {
index 106f00998c3daac770fbbc562d583ba62441c99a..30ab014ec988f1a2fae062bbe36115b003257872 100644 (file)
@@ -98,6 +98,9 @@ STATIC_INIT(C2S_Protocol_renumber) { FOREACH(C2S_Protocol, true, it.m_id = i); }
        .int Version;  // deprecated, use SendFlags
        .int SendFlags;
 
+       IntrusiveList g_uncustomizables;
+       STATIC_INIT(g_uncustomizables) { g_uncustomizables = IL_NEW(); }
+
        void Net_LinkEntity(entity e, bool docull, float dt, bool(entity this, entity to, int sendflags) sendfunc)
        {
                if (e.classname == "") e.classname = "net_linked";
@@ -135,11 +138,13 @@ STATIC_INIT(C2S_Protocol_renumber) { FOREACH(C2S_Protocol, true, it.m_id = i); }
                setcefc(e, customizer);
                e.uncustomizeentityforclient = uncustomizer;
                e.uncustomizeentityforclient_set = !!uncustomizer;
+               if(uncustomizer)
+                       IL_PUSH(g_uncustomizables, e);
        }
 
        void UncustomizeEntitiesRun()
        {
-               FOREACH_ENTITY_FLOAT(uncustomizeentityforclient_set, true, it.uncustomizeentityforclient(it));
+               IL_EACH(g_uncustomizables, it.uncustomizeentityforclient_set, it.uncustomizeentityforclient(it));
        }
 
        STRING_ITERATOR(g_buf, string_null, 0);
@@ -287,7 +292,7 @@ USING(Stream, int);
 #define Read_string() ReadString()
 #define Write_string(to, f) WriteString(to, f)
 
-#ifndef MENUQC
+#ifdef GAMEQC
        const float APPROXPASTTIME_ACCURACY_REQUIREMENT = 0.05;
        #define APPROXPASTTIME_MAX (16384 * APPROXPASTTIME_ACCURACY_REQUIREMENT)
        #define APPROXPASTTIME_RANGE (64 * APPROXPASTTIME_ACCURACY_REQUIREMENT)
index f69b6072bea77316d2b5154a20cf760e92cd3c54..a36466d2e0ffb8daca62e22bd35706bbeb5e761a 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#ifndef MENUQC
+#ifdef GAMEQC
 
     /**
      * Replicate a client cvar into a server field
index bc545b0d0f53721c338fe7b9d6af93b6a5e8bc6b..43bd12314e53f246c25193e81a277dc53580f533 100644 (file)
@@ -66,13 +66,13 @@ SELFWRAP(think, void, (), (entity this), (this))
 #define setthink(e, f) SELFWRAP_SET(think, e, f)
 #define getthink(e) SELFWRAP_GET(think, e)
 
-#ifndef MENUQC
+#ifdef GAMEQC
 SELFWRAP(touch, void, (), (entity this, entity toucher), (this, other))
 #define settouch(e, f) SELFWRAP_SET(touch, e, f)
 #define gettouch(e) SELFWRAP_GET(touch, e)
 #endif
 
-#ifndef MENUQC
+#ifdef GAMEQC
 SELFWRAP(blocked, void, (), (entity this, entity blocker), (this, other))
 #define setblocked(e, f) SELFWRAP_SET(blocked, e, f)
 #define blocked stopusingthis
@@ -81,7 +81,7 @@ SELFWRAP(blocked, void, (), (entity this, entity blocker), (this, other))
 SELFWRAP(predraw, void, (), (entity this), (this))
 #define setpredraw(e, f) SELFWRAP_SET(predraw, e, f)
 
-#ifndef MENUQC
+#ifdef GAMEQC
 SELFWRAP(customizeentityforclient, bool, (), (entity this, entity client), (this, other))
 #define setcefc(e, f) SELFWRAP_SET(customizeentityforclient, e, f)
 #define getcefc(e) SELFWRAP_GET(customizeentityforclient, e)
@@ -104,6 +104,6 @@ SELFWRAP(SendEntity, bool, (entity to, int sendflags), (entity this, entity to,
 #define movetogoal(e, ...) (__self = (e), builtin_movetogoal(__VA_ARGS__))
 #define walkmove(e, ...) (__self = (e), builtin_walkmove(__VA_ARGS__))
 
-#ifndef MENUQC
+#ifdef GAMEQC
 void adaptor_think2use(entity this) { if (this.use) this.use(this, NULL, NULL); }
 #endif
index 10e8ed8c437f98983b55945e0e938bf9f5d73e0f..bb363c12ef26ba5b5dd765200ed08f28dc99519f 100644 (file)
@@ -142,7 +142,7 @@ vector vec_epsilon(vector this, float eps)
 #define ClipVelocity(in, normal, out, overbounce) \
        (out = vec_epsilon(vec_reflect(in, normal, (overbounce) - 1), 0.1))
 
-#ifndef MENUQC
+#ifdef GAMEQC
        vector get_corner_position(entity box, int corner)
        {
                switch (corner)
index cff5be75890ec42062ed7f95db63500d54c91e2a..90e3cd76c983a803a552b32ed7af220aaccb6b6e 100644 (file)
@@ -4,7 +4,7 @@
     #include <common/t_items.qh>
 #elif defined(MENUQC)
 #elif defined(SVQC)
-    #include <common/weapons/all.qh>
+    #include <common/weapons/_all.qh>
 #endif
 
 void WarpZone_Accumulator_Clear(entity acc)
index de692ee8198f06577d1e2f38406e3ed9b0c6e466..34ea2610dedd7afa60e30ce6bab89f7df643940a 100644 (file)
@@ -7,7 +7,7 @@
        #include <common/constants.qh>
        #include <common/triggers/subs.qh>
        #include <common/util.qh>
-       #include <server/command/common.qh>
+       #include <server/command/_mod.qh>
        #include <server/constants.qh>
        #include <server/defs.qh>
 #endif
diff --git a/qcsrc/menu/_all.inc b/qcsrc/menu/_all.inc
new file mode 100644 (file)
index 0000000..e5198f5
--- /dev/null
@@ -0,0 +1,10 @@
+#include <menu/_all.qh>
+#include "_mod.inc"
+
+#include "anim/_mod.inc"
+#include "command/_mod.inc"
+#include "item/_mod.inc"
+#include "mutators/_mod.inc"
+#include "xonotic/_mod.inc"
+
+#include <common/_all.inc>
diff --git a/qcsrc/menu/auto-super.pl b/qcsrc/menu/auto-super.pl
deleted file mode 100644 (file)
index 00926d0..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-my %classoffile = ();
-my %classes = ();
-my %baseclass = ();
-my %methods = ();
-my %attrs = ();
-my %methodnames = ();
-my %old2new = ();
-
-print STDERR "Scanning...\n";
-for my $f(@ARGV)
-{
-       open my $fh, '<', $f;
-       while(<$fh>)
-       {
-               if(/^CLASS\(([^)]*)\)(?:\s*EXTENDS\(([^)]*)\))?/)
-               {
-                       $classes{$1} = defined($2) ? $2 : "Object";
-                       $classoffile{$f} = $1;
-               }
-               if(/^\s*METHOD\(([^),]*),\s*([^),]*)/)
-               {
-                       $methods{$1}{$2} = $1;
-                       $methodnames{"$1"."_"."$2"} = $f;
-                       $old2new{"$2$1"} = "$1"."_"."$2";
-               }
-               if(/^\s*ATTRIB(?:ARRAY)?\(([^),]*),\s*([^),]*)/)
-               {
-                       $attrs{$1}{$2} = $1;
-               }
-       }
-       close $fh;
-}
-
-# propagate down methods etc.
-print STDERR "Propagating...\n";
-for my $class(keys %classes)
-{
-       print STDERR "$class";
-       my $base = $class;
-       for(;;)
-       {
-               $base = $classes{$base};
-               last if not defined $base;
-               print STDERR " -> $base";
-               while(my ($method, $definingclass) = each %{$methods{$base}})
-               {
-                       $methods{$class}{$method} = $definingclass
-                               if not defined $methods{$class}{$method};
-               }
-               while(my ($attr, $definingclass) = each %{$attrs{$base}})
-               {
-                       $attrs{$class}{$attr} = $definingclass
-                               if not defined $attrs{$class}{$attr};
-               }
-       }
-       print STDERR "\n";
-}
-
-# change all calls to base method to super, complain about skipping
-print STDERR "Fixing...\n";
-for my $f(@ARGV)
-{
-       open my $fh, '<', $f;
-       my $s = do { undef local $/; <$fh>; };
-       my $s0 = $s;
-       close $fh;
-
-       my $class = $classoffile{$f};
-       my $base = $classes{$class};
-       next if not defined $base;
-
-       for(keys %old2new)
-       {
-               $s =~ s/\b$_\b/$old2new{$_}/g;
-       }
-
-       my @methods_super = map { [ $methods{$base}{$_} . "_" . $_, "SUPER($class).$_" ]; } keys %{$methods{$base}};
-       for(@methods_super)
-       {
-               my ($search, $replace) = @$_;
-               my $n = ($s =~ s/\b$search\b/$replace/g);
-               print STDERR "[$f] $search -> $replace... $n replacements\n"
-                       if $n;
-       }
-
-       for(grep { $methodnames{$_} ne $f } keys %methodnames)
-       {
-               if($s =~ /\b$_\b/)
-               {
-                       print STDERR "[$f] calls non-super external method directly: $_\n";
-               }
-       }
-
-       if($s ne $s0)
-       {
-               print STDERR "Rewriting $f...\n";
-               open my $fh, '>', $f;
-               print $fh $s;
-               close $fh;
-       }
-}
index e721f357a3953f975ff1b1de84bf0d2f627506d0..0bcef50de71c6d6f4b59d1a8574916f6c2866652 100644 (file)
@@ -1,3 +1,2 @@
 // generated file; do not modify
-#include <menu/command/all.qc>
 #include <menu/command/menu_cmd.qc>
index 5e66557301f031473d87d5506f1ce672af33b80f..91c0a8f35e80a23ccdc487acb7a1ba1853d107e6 100644 (file)
@@ -1,3 +1,2 @@
 // generated file; do not modify
-#include <menu/command/all.qh>
 #include <menu/command/menu_cmd.qh>
diff --git a/qcsrc/menu/command/all.qc b/qcsrc/menu/command/all.qc
deleted file mode 100644 (file)
index 2f8df96..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "all.qh"
-
-#include <common/command/all.qc>
diff --git a/qcsrc/menu/command/all.qh b/qcsrc/menu/command/all.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
index 0f87cbb0959cb38df039f1cac70f796cabd0185b..72aadf6247bac401778744fe630ea81443979fba 100644 (file)
@@ -5,7 +5,7 @@
 
 #include "../mutators/events.qh"
 
-#include <common/command/generic.qh>
+#include <common/command/_mod.qh>
 
 .entity firstChild, nextSibling;
 
index 22934ca908fcf3fcc916f61cae51b2a75630110c..aaa33b137b8ecdcd14fc61d86ec85c7a30c0253b 100644 (file)
@@ -17,8 +17,8 @@
 
 #include "xonotic/util.qh"
 
-#include "../common/items/all.qh"
-#include <common/weapons/all.qh>
+#include "../common/items/_mod.qh"
+#include <common/weapons/_all.qh>
 #include "../common/mapinfo.qh"
 #include "../common/mutators/base.qh"
 
index ad08af93dd5581bb5076865763737d9c20ca2ec4..404c6f2e5a409a588e1014849337e1133fca81fd 100644 (file)
@@ -1,18 +1,9 @@
 #include <lib/_all.inc>
 
 #if XONOTIC
-
-#include "../menu/_mod.inc"
-#include "anim/_mod.inc"
-#include "command/_mod.inc"
-#include "item/_mod.inc"
-#include "mutators/_mod.inc"
-#include "xonotic/_mod.inc"
-
-#include <common/_all.inc>
-
+#include <menu/_all.inc>
 #endif
 
-#if BUILD_MOD
-#include "../../mod/menu/progs.inc"
+#ifdef BUILD_MOD
+#include <mod/menu/progs.inc>
 #endif
index f2f7f5c8e4862fe96cb94e4aaf5ccff6f23221d5..07fe09c100e0bd4a09498dec63b9a6f1bdbdea38 100644 (file)
@@ -1,5 +1,5 @@
 #include "dialog_multiplayer_create_mutators.qh"
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 
 #include "weaponarenacheckbox.qh"
 #include "checkbox.qh"
index 27e488164be5065733501571283131907c86a012..4546a62b109503192359c91904ac49bae9b4053c 100644 (file)
@@ -1,6 +1,6 @@
 #include "keybinder.qh"
 
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 .int flags;
 
 #include "button.qh"
@@ -40,12 +40,13 @@ void Xonotic_KeyBinds_Read()
        KEYBIND_DEF("+fire"                                 , _("primary fire"));
        KEYBIND_DEF("+fire2"                                , _("secondary fire"));
        KEYBIND_DEF(""                                      , "");
-       KEYBIND_DEF(""                                      , _("Weapon switching"));
+       KEYBIND_DEF(""                                      , _("Weapons"));
        KEYBIND_DEF("weapprev"                              , CTX(_("WEAPON^previous")));
        KEYBIND_DEF("weapnext"                              , CTX(_("WEAPON^next")));
        KEYBIND_DEF("weaplast"                              , CTX(_("WEAPON^previously used")));
        KEYBIND_DEF("weapbest"                              , CTX(_("WEAPON^best")));
        KEYBIND_DEF("reload"                                , _("reload"));
+       KEYBIND_DEF("dropweapon"                            , _("drop weapon / throw nade"));
 
        int i;
 
@@ -59,9 +60,9 @@ void Xonotic_KeyBinds_Read()
        for(int imp = 1; imp <= 9; ++imp)
        {
         string w_list = "";
-               ADD_TO_W_LIST(!(it.spawnflags & WEP_FLAG_MUTATORBLOCKED) && !(it.spawnflags & WEP_TYPE_OTHER) && !(it.spawnflags & WEP_FLAG_HIDDEN) && !(it.spawnflags & WEP_FLAG_SUPERWEAPON));
-               ADD_TO_W_LIST((it.spawnflags & WEP_FLAG_SUPERWEAPON) && !(it.spawnflags & WEP_TYPE_OTHER) && !(it.spawnflags & WEP_FLAG_HIDDEN));
-               ADD_TO_W_LIST((it.spawnflags & WEP_FLAG_MUTATORBLOCKED) && !(it.spawnflags & WEP_TYPE_OTHER) && !(it.spawnflags & WEP_FLAG_HIDDEN));
+               ADD_TO_W_LIST(!(it.spawnflags & WEP_FLAG_MUTATORBLOCKED) && !(it.spawnflags & WEP_FLAG_HIDDEN) && !(it.spawnflags & WEP_FLAG_SUPERWEAPON));
+               ADD_TO_W_LIST((it.spawnflags & WEP_FLAG_SUPERWEAPON) && !(it.spawnflags & WEP_FLAG_HIDDEN));
+               ADD_TO_W_LIST((it.spawnflags & WEP_FLAG_MUTATORBLOCKED) && !(it.spawnflags & WEP_FLAG_HIDDEN));
                if(w_list)
                        KEYBIND_DEF(strcat("weapon_group_", itos(imp)), substring(w_list, 0, -4));
                if(imp == 0)
@@ -78,6 +79,8 @@ void Xonotic_KeyBinds_Read()
        KEYBIND_DEF("+showscores"                           , _("show scores"));
        KEYBIND_DEF("screenshot"                            , _("screen shot"));
        KEYBIND_DEF("+hud_panel_radar_maximized"            , _("maximize radar"));
+       KEYBIND_DEF("toggle chase_active"                   , _("3rd person view"));
+       KEYBIND_DEF("spec"                                  , _("enter spectator mode"));
        KEYBIND_DEF(""                                      , "");
        KEYBIND_DEF(""                                      , _("Communicate"));
        KEYBIND_DEF("messagemode"                           , _("public chat"));
@@ -97,12 +100,12 @@ void Xonotic_KeyBinds_Read()
        KEYBIND_DEF("messagemode2"                          , _("team chat"));
        KEYBIND_DEF("team_auto"                             , _("auto-join team"));
        KEYBIND_DEF("menu_showteamselect"                   , _("team menu"));
-       KEYBIND_DEF("menu_showsandboxtools"                 , _("sandbox menu"));
-       KEYBIND_DEF("spec"                                  , _("enter spectator mode"));
-       KEYBIND_DEF("dropweapon"                            , _("drop weapon"));
        KEYBIND_DEF("+use"                                  , _("drop key / drop flag"));
+       KEYBIND_DEF(""                                      , "");
+       KEYBIND_DEF(""                                      , _("Misc"));
+       KEYBIND_DEF("quickmenu"                             , _("quick menu"));
+       KEYBIND_DEF("menu_showsandboxtools"                 , _("sandbox menu"));
        KEYBIND_DEF("+button8"                              , _("drag object"));
-       KEYBIND_DEF("toggle chase_active"                   , _("3rd person view"));
        KEYBIND_DEF(""                                      , "");
        KEYBIND_DEF(""                                      , _("User defined"));
 
index 1a90fa737827bc8e2afaa6b074306d815439d046..c679d4449d7177598dc649228f7e4cc96b11be76 100644 (file)
@@ -38,6 +38,8 @@ void XonoticPlayerModelSelector_loadModels(entity me)
                fn = search_getfilename(glob, i);
                if(!get_model_parameters(fn, -1))
                        continue;
+               if(get_model_parameters_hidden)
+                       continue;
                bufstr_add(sortbuf, sprintf("%-128s%s", get_model_parameters_name, fn), 1);
        }
        search_end(glob);
@@ -49,6 +51,8 @@ void XonoticPlayerModelSelector_loadModels(entity me)
                fn = substring(bufstr_get(sortbuf, i), 128, -1);
                if(!get_model_parameters(fn, -1))
                        error("But it JUST worked!");
+               if(get_model_parameters_hidden)
+                       continue;
                bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_TITLE, get_model_parameters_name);
                bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_IMAGE, strcat("/", substring(get_model_datafilename(get_model_parameters_modelname, get_model_parameters_modelskin, "tga"), 0, -5)));
                bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_MODEL, get_model_parameters_modelname);
index 9cc4da8c38705baeeb633b9607ad7086870848bf..ec76d389e6cd8d9206162aa7645dc8527a8ab3b8 100644 (file)
@@ -7,7 +7,7 @@
 #include <common/constants.qh>
 #include <common/mapinfo.qh>
 #include <common/util.qh>
-#include <common/command/generic.qh>
+#include <common/command/_mod.qh>
 
 float GL_CheckExtension(string ext)
 {
index ed74631dead1b7454724cbe937cb6db0bdf6b72c..7b3d7375b7760018cf4ab267e3f8d2daab6bc137 100644 (file)
@@ -1,6 +1,6 @@
 #include "weaponslist.qh"
 
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 
 .bool disabled;
 
diff --git a/qcsrc/server/_all.inc b/qcsrc/server/_all.inc
new file mode 100644 (file)
index 0000000..3359f13
--- /dev/null
@@ -0,0 +1,18 @@
+#include <server/_all.qh>
+#include "_mod.inc"
+
+#include "bot/_mod.inc"
+#include "command/_mod.inc"
+#include "mutators/_mod.inc"
+#include "pathlib/_mod.inc"
+#include "weapons/_mod.inc"
+
+#include <common/_all.inc>
+#include <common/effects/qc/all.qc>
+
+#include <lib/csqcmodel/sv_model.qc>
+
+#include <lib/warpzone/anglestransform.qc>
+#include <lib/warpzone/common.qc>
+#include <lib/warpzone/server.qc>
+#include <lib/warpzone/util_server.qc>
index f22742f1dda7292b497fc88aeead8ae7d905b997..4ecc610c7d9184f8cf93a510f468297c080ed223 100644 (file)
@@ -3,20 +3,20 @@
 #include <server/antilag.qc>
 #include <server/campaign.qc>
 #include <server/cheats.qc>
-#include <server/cl_client.qc>
-#include <server/cl_impulse.qc>
-#include <server/cl_player.qc>
+#include <server/client.qc>
 #include <server/g_damage.qc>
 #include <server/g_hook.qc>
 #include <server/g_lights.qc>
 #include <server/g_models.qc>
 #include <server/g_subs.qc>
 #include <server/g_world.qc>
+#include <server/impulse.qc>
 #include <server/ipban.qc>
 #include <server/item_key.qc>
 #include <server/mapvoting.qc>
 #include <server/matrix.qc>
 #include <server/miscfunctions.qc>
+#include <server/player.qc>
 #include <server/playerdemo.qc>
 #include <server/portals.qc>
 #include <server/race.qc>
@@ -25,7 +25,9 @@
 #include <server/scores_rules.qc>
 #include <server/spawnpoints.qc>
 #include <server/steerlib.qc>
-#include <server/sv_main.qc>
+#ifdef SVQC
+    #include <server/sv_main.qc>
+#endif
 #include <server/teamplay.qc>
 #include <server/tests.qc>
 #include <server/t_halflife.qc>
index 17e0a829d4531587f92f1777d1aa546a276d83e6..8162606c7834c5c1103648ec2b7cb22977cf2c26 100644 (file)
@@ -3,20 +3,20 @@
 #include <server/antilag.qh>
 #include <server/campaign.qh>
 #include <server/cheats.qh>
-#include <server/cl_client.qh>
-#include <server/cl_impulse.qh>
-#include <server/cl_player.qh>
+#include <server/client.qh>
 #include <server/g_damage.qh>
 #include <server/g_hook.qh>
 #include <server/g_lights.qh>
 #include <server/g_models.qh>
 #include <server/g_subs.qh>
 #include <server/g_world.qh>
+#include <server/impulse.qh>
 #include <server/ipban.qh>
 #include <server/item_key.qh>
 #include <server/mapvoting.qh>
 #include <server/matrix.qh>
 #include <server/miscfunctions.qh>
+#include <server/player.qh>
 #include <server/playerdemo.qh>
 #include <server/portals.qh>
 #include <server/race.qh>
@@ -25,7 +25,9 @@
 #include <server/scores_rules.qh>
 #include <server/spawnpoints.qh>
 #include <server/steerlib.qh>
-#include <server/sv_main.qh>
+#ifdef SVQC
+    #include <server/sv_main.qh>
+#endif
 #include <server/teamplay.qh>
 #include <server/tests.qh>
 #include <server/t_halflife.qh>
index a8d45bd5221ce1cde56fa0e9c8d3dd98fc639898..a1bb5fb958d5da0cdf69d86759fc9b48bfe7de82 100644 (file)
@@ -405,7 +405,8 @@ float autocvar_g_monsters_respawn_delay;
 bool autocvar_g_monsters_respawn;
 float autocvar_g_monsters_armor_blockpercent;
 float autocvar_g_monsters_healthbars;
-float autocvar_g_monsters_lineofsight;
+bool autocvar_g_monsters_lineofsight = true;
+//bool autocvar_g_monsters_ignoretraces = true;
 #define autocvar_g_bloodloss cvar("g_bloodloss")
 bool autocvar_g_nades;
 bool autocvar_g_nades_override_dropweapon = true;
index 8f0672e2623074a3db074eb081ff4bb1c8617ca3..7c0c2882e990915ba7501a21511f2e75469eb62d 100644 (file)
@@ -1,2 +1,5 @@
 // generated file; do not modify
 #include <server/bot/api.qc>
+
+#include <server/bot/default/_mod.inc>
+#include <server/bot/null/_mod.inc>
index 33f0b022911f943822c9b9a9c1ebc27f6e126c89..3678fc69f192bbf66634aa6c66b181dfa6a183e8 100644 (file)
@@ -1,2 +1,5 @@
 // generated file; do not modify
 #include <server/bot/api.qh>
+
+#include <server/bot/default/_mod.qh>
+#include <server/bot/null/_mod.qh>
index 85b0e46568ddad223ba9cce0d67808d616df82ac..274b0340335beed726f58bce67fc0d0db5fd0fc8 100644 (file)
@@ -1,49 +1 @@
 #include "api.qh"
-
-#if 1
-
-#include "default/_mod.inc"
-#include "default/havocbot/_mod.inc"
-
-#else
-
-bool bot_aim(entity this, float shotspeed, float shotspeedupward, float maxshottime, float applygravity) { return false; }
-void bot_clientconnect(entity this) { }
-void bot_clientdisconnect(entity this) { }
-void bot_cmdhelp(string scmd) { }
-void bot_endgame() { }
-bool bot_fixcount() { return true; }
-void bot_list_commands() { }
-void bot_queuecommand(entity bot, string cmdstring) { }
-void bot_relinkplayerlist() { }
-void bot_resetqueues() { }
-void bot_serverframe() { }
-bool bot_shouldattack(entity this, entity e) { return false; }
-void bot_think(entity this) { }
-
-entity find_bot_by_name(string name) { return NULL; }
-entity find_bot_by_number(float number) { return NULL; }
-
-void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius) { }
-void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius) { }
-void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius) { }
-
-entity navigation_findnearestwaypoint(entity ent, float walkfromwp) { return NULL; }
-void navigation_goalrating_end(entity this) { }
-void navigation_goalrating_start(entity this) { }
-void navigation_markroutes(entity this, entity fixed_source_waypoint) { }
-void navigation_markroutes_inverted(entity fixed_source_waypoint) { }
-void navigation_routerating(entity this, entity e, float f, float rangebias) { }
-
-bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float movemode) { return false; }
-
-void waypoint_remove(entity e) { }
-void waypoint_saveall() { }
-void waypoint_schedulerelinkall() { }
-void waypoint_schedulerelink(entity wp) { }
-void waypoint_spawnforitem(entity e) { }
-void waypoint_spawnforitem_force(entity e, vector org) { }
-void waypoint_spawnforteleporter(entity e, vector destination, float timetaken) { }
-void waypoint_spawnforteleporter_v(entity e, vector org, vector destination, float timetaken) { }
-entity waypoint_spawn(vector m1, vector m2, float f) { return NULL; }
-#endif
index 9c525892f952cc9d26d7d8faabc6679a0b111153..64957b92e09c0b7ea7b26e8955cebcc3e784a60f 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 
 const int WAYPOINTFLAG_GENERATED = BIT(23);
 const int WAYPOINTFLAG_ITEM = BIT(22);
@@ -63,7 +63,6 @@ void bot_think(entity this);
 entity find_bot_by_name(string name);
 entity find_bot_by_number(float number);
 
-void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius);
 void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius);
 void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius);
 
index ec73502c3e56d61efdacc510622636baf9070f60..03fb7e0f5bc0893d927a28e8f2b7e9bdba380678 100644 (file)
@@ -5,3 +5,5 @@
 #include <server/bot/default/navigation.qc>
 #include <server/bot/default/scripting.qc>
 #include <server/bot/default/waypoints.qc>
+
+#include <server/bot/default/havocbot/_mod.inc>
index 9252f195e63618fa9401fcd2aed4c244d392301e..04896279bf028c547297c507fa66b6bbe21a8e82 100644 (file)
@@ -5,3 +5,5 @@
 #include <server/bot/default/navigation.qh>
 #include <server/bot/default/scripting.qh>
 #include <server/bot/default/waypoints.qh>
+
+#include <server/bot/default/havocbot/_mod.qh>
index 15dfb0b9b45d96d898a493b6cd91a9f0f3e23ee8..1624676b82ca032b0a7d8d4c65589a1a8d2934bc 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "../../weapons/weaponsystem.qh"
 
-#include "../../mutators/all.qh"
+#include "../../mutators/_mod.qh"
 
 // traces multiple trajectories to find one that will impact the target
 // 'end' vector is the place it aims for,
index cab38143db598d743f377c3556736116782e2f84..ca12d0d651cf53e9caa39a6afa01bd3528a466f8 100644 (file)
 #include "../../antilag.qh"
 #include "../../autocvars.qh"
 #include "../../campaign.qh"
-#include "../../cl_client.qh"
+#include "../../client.qh"
 #include "../../constants.qh"
 #include "../../defs.qh"
 #include "../../race.qh"
 #include <common/t_items.qh>
 
-#include "../../mutators/all.qh"
+#include "../../mutators/_mod.qh"
 
 #include "../../weapons/accuracy.qh"
 
@@ -31,7 +31,9 @@
 #include <common/teams.qh>
 #include <common/util.qh>
 
-#include <common/weapons/all.qh>
+#include <server/scores_rules.qh>
+
+#include <common/weapons/_all.qh>
 
 #include <lib/csqcmodel/sv_model.qh>
 
@@ -434,7 +436,7 @@ void bot_removefromlargestteam()
        int bestcount = 0;
 
        int bcount = 0;
-       FOREACH_ENTITY_FLOAT(isbot, true,
+       FOREACH_CLIENT(it.isbot,
        {
                ++bcount;
 
@@ -484,7 +486,7 @@ void bot_removenewest()
        entity best = NULL;
        int bcount = 0;
 
-       FOREACH_ENTITY_FLOAT(isbot, true,
+       FOREACH_CLIENT(it.isbot,
        {
                ++bcount;
 
index 5ccc80a3a026fa43f6c2e7ea2b59f5a978d898bb..45051b6c270f1e738aa05786b3fbc9f54f1ecc34 100644 (file)
@@ -11,8 +11,9 @@
 #include <common/constants.qh>
 #include <common/physics/player.qh>
 #include <common/state.qh>
-#include <common/items/all.qh>
+#include <common/items/_mod.qh>
 
+#include <common/triggers/teleporters.qh>
 #include <common/triggers/trigger/jumppads.qh>
 
 #include <lib/warpzone/common.qh>
@@ -836,6 +837,26 @@ void havocbot_movetogoal(entity this)
        if (((dodge * v_up) < 0) && random()*frametime >= 0.5*bound(0,(10-skill-this.bot_dodgeskill)*0.1,1)) this.havocbot_ducktime=time+0.3/bound(0.1,skill+this.bot_dodgeskill,10);
 }
 
+entity havocbot_gettarget(entity this, bool secondary)
+{
+       entity best = NULL;
+       vector eye = CENTER_OR_VIEWOFS(this);
+       IL_EACH(g_bot_targets, boolean((secondary) ? it.classname == "misc_breakablemodel" : it.classname != "misc_breakablemodel"),
+       {
+               vector v = CENTER_OR_VIEWOFS(it);
+               if(vdist(v - eye, <, autocvar_bot_ai_enemydetectionradius))
+               if(!best || vlen2(CENTER_OR_VIEWOFS(best) - eye) > vlen2(v - eye))
+               if(bot_shouldattack(this, it))
+               {
+                       traceline(eye, v, true, this);
+                       if (trace_ent == it || trace_fraction >= 1)
+                               best = it;
+               }
+       });
+
+       return best;
+}
+
 void havocbot_chooseenemy(entity this)
 {
        entity head, best, head2;
@@ -1214,7 +1235,7 @@ float havocbot_moveto(entity this, vector pos)
        this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_LINKING;
 
        // if pos is inside a teleport, then let's mark it as teleport waypoint
-       FOREACH_ENTITY_CLASS("trigger_teleport", WarpZoneLib_BoxTouchesBrush(pos, pos, it, NULL),
+       IL_EACH(g_teleporters, WarpZoneLib_BoxTouchesBrush(pos, pos, it, NULL),
        {
                wp.wpflags |= WAYPOINTFLAG_TELEPORT;
                this.lastteleporttime = 0;
index 771ab282ddd49039f36fcfbed52a8cb24ccb18c1..dcf18ef19b1f3622a1eb12590ec66d937d51add9 100644 (file)
@@ -19,7 +19,7 @@ void havocbot_goalrating_items(entity this, float ratingscale, vector org, float
        vector o;
        ratingscale = ratingscale * 0.0001; // items are rated around 10000 already
 
-       FOREACH_ENTITY_FLOAT(bot_pickup, true,
+       IL_EACH(g_items, it.bot_pickup,
        {
                o = (it.absmin + it.absmax) * 0.5;
                friend_distance = 10000; enemy_distance = 10000;
@@ -118,19 +118,6 @@ void havocbot_goalrating_items(entity this, float ratingscale, vector org, float
        });
 }
 
-void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius)
-{
-       FOREACH_ENTITY_CLASS("dom_controlpoint", vdist((((it.absmin + it.absmax) * 0.5) - org), <, sradius),
-       {
-               if(it.cnt > -1) // this is just being fought
-                       navigation_routerating(this, it, ratingscale, 5000);
-               else if(it.goalentity.cnt == 0) // unclaimed
-                       navigation_routerating(this, it, ratingscale * 0.5, 5000);
-               else if(it.goalentity.team != this.team) // other team's point
-                       navigation_routerating(this, it, ratingscale * 0.2, 5000);
-       });
-}
-
 void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius)
 {
        if (autocvar_bot_nofire)
index 5b1f2b530de231e60d79dd03f76ea8d758e66809..6f70f09beec2219624baeca92e2cd7deaa104fb4 100644 (file)
@@ -1,2 +1 @@
 #pragma once
-void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius);
index 1d18a582ed3864c10d1d3f4063c30dfd91e0f040..0c563d1ff9e2f1953775caa14b437171fe74c480 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <common/t_items.qh>
 
-#include <common/items/all.qh>
+#include <common/items/_mod.qh>
 
 #include <common/constants.qh>
 #include <common/triggers/trigger/jumppads.qh>
@@ -1000,7 +1000,7 @@ void botframe_updatedangerousobjects(float maxupdate)
                danger = 0;
                m1 = it.mins;
                m2 = it.maxs;
-               FOREACH_ENTITY_FLOAT(bot_dodge, true,
+               IL_EACH(g_bot_dodge, it.bot_dodge,
                {
                        v = it.origin;
                        v.x = bound(m1_x, v.x, m2_x);
index e111b2ab4f043f5174b270b5090f6190a3dfb5c1..fa273410ea6882bd012daff70dffe93c67c17743 100644 (file)
@@ -230,17 +230,10 @@ void bot_commands_init()
 // Returns first bot with matching name
 entity find_bot_by_name(string name)
 {
-       entity bot;
-
-       bot = findchainflags(flags, FL_CLIENT);
-       while (bot)
+       FOREACH_CLIENT(IS_BOT_CLIENT(it) && it.netname == name,
        {
-               if(IS_BOT_CLIENT(bot))
-               if(bot.netname==name)
-                       return bot;
-
-               bot = bot.chain;
-       }
+               return it;
+       });
 
        return NULL;
 }
index 8475640ac7086462ab73f087d6b8fc9603f285c5..5fb923799acfa41f863414a7ed96d33253874acd 100644 (file)
@@ -34,7 +34,7 @@ entity waypoint_spawn(vector m1, vector m2, float f)
        w.solid = SOLID_TRIGGER;
        setorigin(w, (m1 + m2) * 0.5);
        setsize(w, m1 - w.origin, m2 - w.origin);
-       if (vlen(w.size) > 0)
+       if (w.size)
                w.wpisbox = true;
 
        if(!w.wpisbox)
@@ -280,7 +280,7 @@ void waypoint_schedulerelink(entity wp)
        }
        else
                wp.model = "";
-       wp.wpisbox = vlen(wp.size) > 0;
+       wp.wpisbox = vdist(wp.size, >, 0);
        wp.enemy = NULL;
        if (!(wp.wpflags & WAYPOINTFLAG_PERSONAL))
                wp.owner = NULL;
@@ -1012,7 +1012,7 @@ void botframe_autowaypoints_fix(entity p, float walkfromwp, .entity fld)
 
 void botframe_deleteuselesswaypoints()
 {
-       FOREACH_ENTITY_FLOAT(bot_pickup, true,
+       IL_EACH(g_items, it.bot_pickup,
        {
                // NOTE: this protects waypoints if they're the ONLY nearest
                // waypoint. That's the intention.
diff --git a/qcsrc/server/bot/null/_mod.inc b/qcsrc/server/bot/null/_mod.inc
new file mode 100644 (file)
index 0000000..d40f451
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <server/bot/null/bot_null.qc>
diff --git a/qcsrc/server/bot/null/_mod.qh b/qcsrc/server/bot/null/_mod.qh
new file mode 100644 (file)
index 0000000..0449a1c
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <server/bot/null/bot_null.qh>
diff --git a/qcsrc/server/bot/null/bot_null.qc b/qcsrc/server/bot/null/bot_null.qc
new file mode 100644 (file)
index 0000000..b4102cb
--- /dev/null
@@ -0,0 +1,42 @@
+#include "bot_null.qh"
+
+#if 0
+bool bot_aim(entity this, float shotspeed, float shotspeedupward, float maxshottime, float applygravity) { return false; }
+void bot_clientconnect(entity this) { }
+void bot_clientdisconnect(entity this) { }
+void bot_cmdhelp(string scmd) { }
+void bot_endgame() { }
+bool bot_fixcount() { return true; }
+void bot_list_commands() { }
+void bot_queuecommand(entity bot, string cmdstring) { }
+void bot_relinkplayerlist() { }
+void bot_resetqueues() { }
+void bot_serverframe() { }
+bool bot_shouldattack(entity this, entity e) { return false; }
+void bot_think(entity this) { }
+
+entity find_bot_by_name(string name) { return NULL; }
+entity find_bot_by_number(float number) { return NULL; }
+
+void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius) { }
+void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius) { }
+
+entity navigation_findnearestwaypoint(entity ent, float walkfromwp) { return NULL; }
+void navigation_goalrating_end(entity this) { }
+void navigation_goalrating_start(entity this) { }
+void navigation_markroutes(entity this, entity fixed_source_waypoint) { }
+void navigation_markroutes_inverted(entity fixed_source_waypoint) { }
+void navigation_routerating(entity this, entity e, float f, float rangebias) { }
+
+bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float movemode) { return false; }
+
+void waypoint_remove(entity e) { }
+void waypoint_saveall() { }
+void waypoint_schedulerelinkall() { }
+void waypoint_schedulerelink(entity wp) { }
+void waypoint_spawnforitem(entity e) { }
+void waypoint_spawnforitem_force(entity e, vector org) { }
+void waypoint_spawnforteleporter(entity e, vector destination, float timetaken) { }
+void waypoint_spawnforteleporter_v(entity e, vector org, vector destination, float timetaken) { }
+entity waypoint_spawn(vector m1, vector m2, float f) { return NULL; }
+#endif
diff --git a/qcsrc/server/bot/null/bot_null.qh b/qcsrc/server/bot/null/bot_null.qh
new file mode 100644 (file)
index 0000000..28709a2
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma once
+
+#include "../api.qh"
index f31b3e5c2fba778c65c908de8aba6d2ef89d2528..9f763a886d73217cd4490aa05fba9f75a2add448 100644 (file)
@@ -4,7 +4,7 @@
 #include "race.qh"
 #include "../common/triggers/teleporters.qh"
 
-#include "mutators/all.qh"
+#include "mutators/_mod.qh"
 
 #include "weapons/tracing.qh"
 
@@ -14,9 +14,9 @@
 
 #include <common/physics/player.qh>
 
-#include "../common/monsters/all.qh"
+#include "../common/monsters/_mod.qh"
 
-#include "../common/weapons/all.qh"
+#include <common/weapons/_all.qh>
 
 #include "../common/triggers/subs.qh"
 
@@ -913,7 +913,7 @@ void Drag_Finish(entity dragger)
                        break;
        }
 
-       if((draggee.flags & FL_ITEM) && (vlen(draggee.velocity) < 32))
+       if((draggee.flags & FL_ITEM) && (vdist(draggee.velocity, <, 32)))
        {
                draggee.velocity = '0 0 0';
                SET_ONGROUND(draggee); // floating items are FUN
diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc
deleted file mode 100644 (file)
index 0a608e9..0000000
+++ /dev/null
@@ -1,2594 +0,0 @@
-#include "cl_client.qh"
-
-#include "anticheat.qh"
-#include "cl_impulse.qh"
-#include "cl_player.qh"
-#include "ipban.qh"
-#include "miscfunctions.qh"
-#include "portals.qh"
-#include "teamplay.qh"
-#include "playerdemo.qh"
-#include "spawnpoints.qh"
-#include "g_damage.qh"
-#include "g_hook.qh"
-#include "command/common.qh"
-#include "cheats.qh"
-#include "g_world.qh"
-#include "race.qh"
-#include "antilag.qh"
-#include "campaign.qh"
-#include "command/common.qh"
-
-#include "bot/api.qh"
-
-#include "../common/ent_cs.qh"
-#include <common/state.qh>
-
-#include <common/effects/qc/globalsound.qh>
-
-#include "../common/triggers/teleporters.qh"
-
-#include "../common/vehicles/all.qh"
-
-#include "weapons/hitplot.qh"
-#include "weapons/weaponsystem.qh"
-
-#include "../common/net_notice.qh"
-#include "../common/physics/player.qh"
-
-#include "../common/items/all.qc"
-
-#include "../common/mutators/mutator/waypoints/all.qh"
-
-#include "../common/triggers/subs.qh"
-#include "../common/triggers/triggers.qh"
-#include "../common/triggers/trigger/secret.qh"
-
-#include "../common/minigames/sv_minigames.qh"
-
-#include "../common/items/inventory.qh"
-
-#include "../common/monsters/sv_monsters.qh"
-
-#include "../lib/warpzone/server.qh"
-
-STATIC_METHOD(Client, Add, void(Client this, int _team))
-{
-    ClientConnect(this);
-    TRANSMUTE(Player, this);
-    this.frame = 12; // 7
-    this.team = _team;
-    PutClientInServer(this);
-}
-
-void PutObserverInServer(entity this);
-
-STATIC_METHOD(Client, Remove, void(Client this))
-{
-    TRANSMUTE(Observer, this);
-    PutClientInServer(this);
-    ClientDisconnect(this);
-}
-
-void send_CSQC_teamnagger() {
-       WriteHeader(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
-}
-
-int CountSpectators(entity player, entity to)
-{
-       if(!player) { return 0; } // not sure how, but best to be safe
-
-       int spec_count = 0;
-
-       FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
-       {
-               spec_count++;
-       });
-
-       return spec_count;
-}
-
-void WriteSpectators(entity player, entity to)
-{
-       if(!player) { return; } // not sure how, but best to be safe
-
-       FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
-       {
-               WriteByte(MSG_ENTITY, num_for_edict(it));
-       });
-}
-
-bool ClientData_Send(entity this, entity to, int sf)
-{
-       assert(to == this.owner, return false);
-
-       entity e = to;
-       if (IS_SPEC(e)) e = e.enemy;
-
-       sf = 0;
-       if (e.race_completed)       sf |= 1; // forced scoreboard
-       if (to.spectatee_status)    sf |= 2; // spectator ent number follows
-       if (e.zoomstate)            sf |= 4; // zoomed
-       if (e.porto_v_angle_held)   sf |= 8; // angles held
-       if (autocvar_sv_showspectators) sf |= 16; // show spectators
-
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA);
-       WriteByte(MSG_ENTITY, sf);
-
-       if (sf & 2)
-       {
-               WriteByte(MSG_ENTITY, to.spectatee_status);
-       }
-       if (sf & 8)
-       {
-               WriteAngle(MSG_ENTITY, e.v_angle.x);
-               WriteAngle(MSG_ENTITY, e.v_angle.y);
-       }
-
-       if(sf & 16)
-       {
-               float specs = CountSpectators(e, to);
-               WriteByte(MSG_ENTITY, specs);
-               WriteSpectators(e, to);
-       }
-
-       return true;
-}
-
-void ClientData_Attach(entity this)
-{
-       Net_LinkEntity(this.clientdata = new_pure(clientdata), false, 0, ClientData_Send);
-       this.clientdata.drawonlytoclient = this;
-       this.clientdata.owner = this;
-}
-
-void ClientData_Detach(entity this)
-{
-       delete(this.clientdata);
-       this.clientdata = NULL;
-}
-
-void ClientData_Touch(entity e)
-{
-       e.clientdata.SendFlags = 1;
-
-       // make it spectatable
-       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != e && IS_SPEC(it) && it.enemy == e, LAMBDA(it.clientdata.SendFlags = 1));
-}
-
-.string netname_previous;
-
-void SetSpectatee(entity player, entity spectatee);
-
-
-/*
-=============
-CheckPlayerModel
-
-Checks if the argument string can be a valid playermodel.
-Returns a valid one in doubt.
-=============
-*/
-string FallbackPlayerModel;
-string CheckPlayerModel(string plyermodel) {
-       if(FallbackPlayerModel != cvar_defstring("_cl_playermodel"))
-       {
-               // note: we cannot summon Don Strunzone here, some player may
-               // still have the model string set. In case anyone manages how
-               // to change a cvar default, we'll have a small leak here.
-               FallbackPlayerModel = strzone(cvar_defstring("_cl_playermodel"));
-       }
-       // only in right path
-       if( substring(plyermodel,0,14) != "models/player/")
-               return FallbackPlayerModel;
-       // only good file extensions
-       if(substring(plyermodel,-4,4) != ".zym")
-       if(substring(plyermodel,-4,4) != ".dpm")
-       if(substring(plyermodel,-4,4) != ".iqm")
-       if(substring(plyermodel,-4,4) != ".md3")
-       if(substring(plyermodel,-4,4) != ".psk")
-               return FallbackPlayerModel;
-       // forbid the LOD models
-       if(substring(plyermodel, -9,5) == "_lod1")
-               return FallbackPlayerModel;
-       if(substring(plyermodel, -9,5) == "_lod2")
-               return FallbackPlayerModel;
-       if(plyermodel != strtolower(plyermodel))
-               return FallbackPlayerModel;
-       // also, restrict to server models
-       if(autocvar_sv_servermodelsonly)
-       {
-               if(!fexists(plyermodel))
-                       return FallbackPlayerModel;
-       }
-       return plyermodel;
-}
-
-void setplayermodel(entity e, string modelname)
-{
-       precache_model(modelname);
-       _setmodel(e, modelname);
-       player_setupanimsformodel(e);
-       if(!autocvar_g_debug_globalsounds)
-               UpdatePlayerSounds(e);
-}
-
-void FixPlayermodel(entity player);
-/** putting a client as observer in the server */
-void PutObserverInServer(entity this)
-{
-    bool mutator_returnvalue = MUTATOR_CALLHOOK(MakePlayerObserver, this);
-       PlayerState_detach(this);
-
-       if (IS_PLAYER(this) && this.health >= 1) {
-        // despawn effect
-               Send_Effect(EFFECT_SPAWN_NEUTRAL, this.origin, '0 0 0', 1);
-    }
-
-    {
-        entity spot = SelectSpawnPoint(this, true);
-        if (!spot) LOG_FATAL("No spawnpoints for observers?!?");
-        this.angles = spot.angles;
-        this.angles_z = 0;
-        this.fixangle = true;
-        // offset it so that the spectator spawns higher off the ground, looks better this way
-        setorigin(this, spot.origin + STAT(PL_VIEW_OFS, NULL));
-        this.prevorigin = this.origin;
-        if (IS_REAL_CLIENT(this))
-        {
-            msg_entity = this;
-            WriteByte(MSG_ONE, SVC_SETVIEW);
-            WriteEntity(MSG_ONE, this);
-        }
-        // give the spectator some space between walls for MOVETYPE_FLY_WORLDONLY
-        // so that your view doesn't go into the ceiling with MOVETYPE_FLY_WORLDONLY, previously "PL_VIEW_OFS"
-        if(!autocvar_g_debug_globalsounds)
-        {
-               // needed for player sounds
-               this.model = "";
-               FixPlayermodel(this);
-        }
-        setmodel(this, MDL_Null);
-        setsize(this, STAT(PL_CROUCH_MIN, NULL), STAT(PL_CROUCH_MAX, NULL));
-        this.view_ofs = '0 0 0';
-    }
-
-    RemoveGrapplingHook(this);
-       Portal_ClearAll(this);
-       Unfreeze(this);
-       SetSpectatee(this, NULL);
-
-       if (this.alivetime)
-       {
-               if (!warmup_stage)
-                       PS_GR_P_ADDVAL(this, PLAYERSTATS_ALIVETIME, time - this.alivetime);
-               this.alivetime = 0;
-       }
-
-       if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE);
-
-       WaypointSprite_PlayerDead(this);
-
-       if (mutator_returnvalue) {
-           // mutator prevents resetting teams+score
-       } else {
-               this.team = -1;  // move this as it is needed to log the player spectating in eventlog
-        this.frags = FRAGS_SPECTATOR;
-        PlayerScore_Clear(this);  // clear scores when needed
-    }
-
-       if (this.killcount != FRAGS_SPECTATOR)
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, this.netname);
-               if(!intermission_running)
-               if(autocvar_g_chat_nospectators == 1 || (!(warmup_stage || gameover) && autocvar_g_chat_nospectators == 2))
-                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CHAT_NOSPECTATORS);
-
-               if(this.just_joined == false) {
-                       LogTeamchange(this.playerid, -1, 4);
-               } else
-                       this.just_joined = false;
-       }
-
-       accuracy_resend(this);
-
-       this.spectatortime = time;
-       this.bot_attack = false;
-    this.hud = HUD_NORMAL;
-       TRANSMUTE(Observer, this);
-       this.iscreature = false;
-       this.teleportable = TELEPORT_SIMPLE;
-       this.damagedbycontents = false;
-       this.health = FRAGS_SPECTATOR;
-       this.takedamage = DAMAGE_NO;
-       this.solid = SOLID_NOT;
-       set_movetype(this, MOVETYPE_FLY_WORLDONLY); // user preference is controlled by playerprethink
-       this.flags = FL_CLIENT | FL_NOTARGET;
-       this.armorvalue = 666;
-       this.effects = 0;
-       this.armorvalue = autocvar_g_balance_armor_start;
-       this.pauserotarmor_finished = 0;
-       this.pauserothealth_finished = 0;
-       this.pauseregen_finished = 0;
-       this.damageforcescale = 0;
-       this.death_time = 0;
-       this.respawn_flags = 0;
-       this.respawn_time = 0;
-       this.stat_respawn_time = 0;
-       this.alpha = 0;
-       this.scale = 0;
-       this.fade_time = 0;
-       this.pain_frame = 0;
-       this.pain_finished = 0;
-       this.strength_finished = 0;
-       this.invincible_finished = 0;
-       this.superweapons_finished = 0;
-       this.pushltime = 0;
-       this.istypefrag = 0;
-       setthink(this, func_null);
-       this.nextthink = 0;
-       this.hook_time = 0;
-       this.deadflag = DEAD_NO;
-       this.crouch = false;
-       this.revival_time = 0;
-
-       this.items = 0;
-       this.weapons = '0 0 0';
-       this.drawonlytoclient = this;
-
-       this.weaponname = "";
-       this.weaponmodel = "";
-       for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-       {
-               this.weaponentities[slot] = NULL;
-       }
-       this.exteriorweaponentity = NULL;
-       this.killcount = FRAGS_SPECTATOR;
-       this.velocity = '0 0 0';
-       this.avelocity = '0 0 0';
-       this.punchangle = '0 0 0';
-       this.punchvector = '0 0 0';
-       this.oldvelocity = this.velocity;
-       this.fire_endtime = -1;
-       this.event_damage = func_null;
-
-       STAT(ACTIVEWEAPON, this) = WEP_Null.m_id;
-       STAT(SWITCHINGWEAPON, this) = WEP_Null.m_id;
-       STAT(SWITCHWEAPON, this) = WEP_Null.m_id;
-}
-
-int player_getspecies(entity this)
-{
-       get_model_parameters(this.model, this.skin);
-       int s = get_model_parameters_species;
-       get_model_parameters(string_null, 0);
-       if (s < 0) return SPECIES_HUMAN;
-       return s;
-}
-
-.float model_randomizer;
-void FixPlayermodel(entity player)
-{
-       string defaultmodel = "";
-       int defaultskin = 0;
-       if(autocvar_sv_defaultcharacter)
-       {
-               if(teamplay)
-               {
-                       string s = Static_Team_ColorName_Lower(player.team);
-                       if (s != "neutral")
-                       {
-                               defaultmodel = cvar_string(strcat("sv_defaultplayermodel_", s));
-                               defaultskin = cvar(strcat("sv_defaultplayerskin_", s));
-                       }
-               }
-
-               if(defaultmodel == "")
-               {
-                       defaultmodel = autocvar_sv_defaultplayermodel;
-                       defaultskin = autocvar_sv_defaultplayerskin;
-               }
-
-               int n = tokenize_console(defaultmodel);
-               if(n > 0)
-               {
-                       defaultmodel = argv(floor(n * player.model_randomizer));
-                       // However, do NOT randomize if the player-selected model is in the list.
-                       for (int i = 0; i < n; ++i)
-                               if ((argv(i) == player.playermodel && defaultskin == stof(player.playerskin)) || argv(i) == strcat(player.playermodel, ":", player.playerskin))
-                                       defaultmodel = argv(i);
-               }
-
-               int i = strstrofs(defaultmodel, ":", 0);
-               if(i >= 0)
-               {
-                       defaultskin = stof(substring(defaultmodel, i+1, -1));
-                       defaultmodel = substring(defaultmodel, 0, i);
-               }
-       }
-       if(autocvar_sv_defaultcharacterskin && !defaultskin)
-       {
-               if(teamplay)
-               {
-                       string s = Static_Team_ColorName_Lower(player.team);
-                       if (s != "neutral")
-                               defaultskin = cvar(strcat("sv_defaultplayerskin_", s));
-               }
-
-               if(!defaultskin)
-                       defaultskin = autocvar_sv_defaultplayerskin;
-       }
-
-       MUTATOR_CALLHOOK(FixPlayermodel, defaultmodel, defaultskin, player);
-       defaultmodel = M_ARGV(0, string);
-       defaultskin = M_ARGV(1, int);
-
-       bool chmdl = false;
-       int oldskin;
-       if(defaultmodel != "")
-       {
-               if (defaultmodel != player.model)
-               {
-                       vector m1 = player.mins;
-                       vector m2 = player.maxs;
-                       setplayermodel (player, defaultmodel);
-                       setsize (player, m1, m2);
-                       chmdl = true;
-               }
-
-               oldskin = player.skin;
-               player.skin = defaultskin;
-       } else {
-               if (player.playermodel != player.model || player.playermodel == "")
-               {
-                       player.playermodel = CheckPlayerModel(player.playermodel); // this is never "", so no endless loop
-                       vector m1 = player.mins;
-                       vector m2 = player.maxs;
-                       setplayermodel (player, player.playermodel);
-                       setsize (player, m1, m2);
-                       chmdl = true;
-               }
-
-               if(!autocvar_sv_defaultcharacterskin)
-               {
-                       oldskin = player.skin;
-                       player.skin = stof(player.playerskin);
-               }
-               else
-               {
-                       oldskin = player.skin;
-                       player.skin = defaultskin;
-               }
-       }
-
-       if(chmdl || oldskin != player.skin) // model or skin has changed
-       {
-               player.species = player_getspecies(player); // update species
-               if(!autocvar_g_debug_globalsounds)
-                       UpdatePlayerSounds(player); // update skin sounds
-       }
-
-       if(!teamplay)
-               if(strlen(autocvar_sv_defaultplayercolors))
-                       if(player.clientcolors != stof(autocvar_sv_defaultplayercolors))
-                               setcolor(player, stof(autocvar_sv_defaultplayercolors));
-}
-
-
-/** Called when a client spawns in the server */
-void PutClientInServer(entity this)
-{
-       if (IS_BOT_CLIENT(this)) {
-               TRANSMUTE(Player, this);
-       } else if (IS_REAL_CLIENT(this)) {
-               msg_entity = this;
-               WriteByte(MSG_ONE, SVC_SETVIEW);
-               WriteEntity(MSG_ONE, this);
-       }
-       if (gameover) {
-               TRANSMUTE(Observer, this);
-       }
-
-       SetSpectatee(this, NULL);
-
-       // reset player keys
-       this.itemkeys = 0;
-
-       MUTATOR_CALLHOOK(PutClientInServer, this);
-
-       if (IS_OBSERVER(this)) {
-               PutObserverInServer(this);
-       } else if (IS_PLAYER(this)) {
-               if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE);
-
-               PlayerState_attach(this);
-               accuracy_resend(this);
-
-               if (this.team < 0)
-                       JoinBestTeam(this, false, true);
-
-               entity spot = SelectSpawnPoint(this, false);
-               if (!spot) {
-                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_NOSPAWNS);
-                       return; // spawn failed
-               }
-
-               TRANSMUTE(Player, this);
-               this.wasplayer = true;
-               this.iscreature = true;
-               this.teleportable = TELEPORT_NORMAL;
-               this.damagedbycontents = true;
-               set_movetype(this, MOVETYPE_WALK);
-               this.solid = SOLID_SLIDEBOX;
-               this.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID;
-               if (autocvar_g_playerclip_collisions)
-                       this.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP;
-               if (IS_BOT_CLIENT(this) && autocvar_g_botclip_collisions)
-                       this.dphitcontentsmask |= DPCONTENTS_BOTCLIP;
-               this.frags = FRAGS_PLAYER;
-               if (INDEPENDENT_PLAYERS) MAKE_INDEPENDENT_PLAYER(this);
-               this.flags = FL_CLIENT | FL_PICKUPITEMS;
-               if (autocvar__notarget)
-                       this.flags |= FL_NOTARGET;
-               this.takedamage = DAMAGE_AIM;
-               this.effects = EF_TELEPORT_BIT | EF_RESTARTANIM_BIT;
-               this.dmg = 2; // WTF
-
-               if (warmup_stage) {
-                       this.ammo_shells = warmup_start_ammo_shells;
-                       this.ammo_nails = warmup_start_ammo_nails;
-                       this.ammo_rockets = warmup_start_ammo_rockets;
-                       this.ammo_cells = warmup_start_ammo_cells;
-                       this.ammo_plasma = warmup_start_ammo_plasma;
-                       this.ammo_fuel = warmup_start_ammo_fuel;
-                       this.health = warmup_start_health;
-                       this.armorvalue = warmup_start_armorvalue;
-                       this.weapons = WARMUP_START_WEAPONS;
-               } else {
-                       this.ammo_shells = start_ammo_shells;
-                       this.ammo_nails = start_ammo_nails;
-                       this.ammo_rockets = start_ammo_rockets;
-                       this.ammo_cells = start_ammo_cells;
-                       this.ammo_plasma = start_ammo_plasma;
-                       this.ammo_fuel = start_ammo_fuel;
-                       this.health = start_health;
-                       this.armorvalue = start_armorvalue;
-                       this.weapons = start_weapons;
-               }
-
-               this.superweapons_finished = (this.weapons & WEPSET_SUPERWEAPONS) ? time + autocvar_g_balance_superweapons_time : 0;
-
-               this.items = start_items;
-
-               this.spawnshieldtime = time + autocvar_g_spawnshieldtime;
-               this.pauserotarmor_finished = time + autocvar_g_balance_pause_armor_rot_spawn;
-               this.pauserothealth_finished = time + autocvar_g_balance_pause_health_rot_spawn;
-               this.pauserotfuel_finished = time + autocvar_g_balance_pause_fuel_rot_spawn;
-               this.pauseregen_finished = time + autocvar_g_balance_pause_health_regen_spawn;
-               // extend the pause of rotting if client was reset at the beginning of the countdown
-               if (!autocvar_sv_ready_restart_after_countdown && time < game_starttime) { // TODO why is this cvar NOTted?
-                       float f = game_starttime - time;
-                       this.spawnshieldtime += f;
-                       this.pauserotarmor_finished += f;
-                       this.pauserothealth_finished += f;
-                       this.pauseregen_finished += f;
-               }
-               this.damageforcescale = 2;
-               this.death_time = 0;
-               this.respawn_flags = 0;
-               this.respawn_time = 0;
-               this.stat_respawn_time = 0;
-               this.scale = autocvar_sv_player_scale;
-               this.fade_time = 0;
-               this.pain_frame = 0;
-               this.pain_finished = 0;
-               this.pushltime = 0;
-               setthink(this, func_null); // players have no think function
-               this.nextthink = 0;
-               this.dmg_team = 0;
-               this.ballistics_density = autocvar_g_ballistics_density_player;
-
-               this.deadflag = DEAD_NO;
-
-               this.angles = spot.angles;
-               this.angles_z = 0; // never spawn tilted even if the spot says to
-               if (IS_BOT_CLIENT(this))
-                       this.v_angle = this.angles;
-               this.fixangle = true; // turn this way immediately
-               this.oldvelocity = this.velocity = '0 0 0';
-               this.avelocity = '0 0 0';
-               this.punchangle = '0 0 0';
-               this.punchvector = '0 0 0';
-
-               this.strength_finished = 0;
-               this.invincible_finished = 0;
-               this.fire_endtime = -1;
-               this.revival_time = 0;
-               this.air_finished = time + 12;
-
-               entity spawnevent = new_pure(spawnevent);
-               spawnevent.owner = this;
-               Net_LinkEntity(spawnevent, false, 0.5, SpawnEvent_Send);
-
-               // Cut off any still running player sounds.
-               stopsound(this, CH_PLAYER_SINGLE);
-
-               this.model = "";
-               FixPlayermodel(this);
-               this.drawonlytoclient = NULL;
-
-               this.crouch = false;
-               this.view_ofs = STAT(PL_VIEW_OFS, NULL);
-               setsize(this, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL));
-               this.spawnorigin = spot.origin;
-               setorigin(this, spot.origin + '0 0 1' * (1 - this.mins.z - 24));
-               // don't reset back to last position, even if new position is stuck in solid
-               this.oldorigin = this.origin;
-               this.prevorigin = this.origin;
-               this.lastteleporttime = time; // prevent insane speeds due to changing origin
-               this.conveyor = NULL; // prevent conveyors at the previous location from moving a freshly spawned player
-               this.hud = HUD_NORMAL;
-
-               this.event_damage = PlayerDamage;
-
-               this.bot_attack = true;
-               this.monster_attack = true;
-
-               PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_JUMP(this) = PHYS_INPUT_BUTTON_ATCK2(this) = false;
-
-               if (this.killcount == FRAGS_SPECTATOR) {
-                       PlayerScore_Clear(this);
-                       this.killcount = 0;
-               }
-
-               for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-               {
-                       CL_SpawnWeaponentity(this, weaponentities[slot]);
-               }
-               this.alpha = default_player_alpha;
-               this.colormod = '1 1 1' * autocvar_g_player_brightness;
-               this.exteriorweaponentity.alpha = default_weapon_alpha;
-
-               this.speedrunning = false;
-
-               target_voicescript_clear(this);
-
-               // reset fields the weapons may use
-               FOREACH(Weapons, true, LAMBDA(
-                       it.wr_resetplayer(it, this);
-                       // reload all reloadable weapons
-                       if (it.spawnflags & WEP_FLAG_RELOADABLE) {
-                               this.weapon_load[it.m_id] = it.reloading_ammo;
-                       }
-               ));
-
-               {
-                       string s = spot.target;
-                       spot.target = string_null;
-                       SUB_UseTargets(spot, this, NULL);
-                       spot.target = s;
-               }
-
-               Unfreeze(this);
-
-               MUTATOR_CALLHOOK(PlayerSpawn, this, spot);
-
-               if (autocvar_spawn_debug)
-               {
-                       sprint(this, strcat("spawnpoint origin:  ", vtos(spot.origin), "\n"));
-                       delete(spot); // usefull for checking if there are spawnpoints, that let drop through the floor
-               }
-
-               PS(this).m_switchweapon = w_getbestweapon(this);
-               this.cnt = -1; // W_LastWeapon will not complain
-               PS(this).m_weapon = WEP_Null;
-               this.weaponname = "";
-               PS(this).m_switchingweapon = WEP_Null;
-
-               if (!warmup_stage && !this.alivetime)
-                       this.alivetime = time;
-
-               antilag_clear(this, CS(this));
-       }
-}
-
-void ClientInit_misc(entity this);
-
-.float ebouncefactor, ebouncestop; // electro's values
-// TODO do we need all these fields, or should we stop autodetecting runtime
-// changes and just have a console command to update this?
-bool ClientInit_SendEntity(entity this, entity to, int sf)
-{
-       WriteHeader(MSG_ENTITY, _ENT_CLIENT_INIT);
-       return = true;
-       msg_entity = to;
-       // MSG_INIT replacement
-       // TODO: make easier to use
-       Registry_send_all();
-       W_PROP_reload(MSG_ONE, to);
-       ClientInit_misc(this);
-       MUTATOR_CALLHOOK(Ent_Init);
-}
-void ClientInit_misc(entity this)
-{
-       int channel = MSG_ONE;
-       WriteHeader(channel, ENT_CLIENT_INIT);
-       WriteByte(channel, g_nexball_meter_period * 32);
-       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[0]));
-       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[1]));
-       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[2]));
-       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[3]));
-       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[0]));
-       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[1]));
-       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[2]));
-       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[3]));
-
-       if(sv_foginterval && world.fog != "")
-               WriteString(channel, world.fog);
-       else
-               WriteString(channel, "");
-       WriteByte(channel, this.count * 255.0); // g_balance_armor_blockpercent
-       WriteByte(channel, serverflags); // client has to know if it should zoom or not
-       WriteCoord(channel, autocvar_g_trueaim_minrange);
-}
-
-void ClientInit_CheckUpdate(entity this)
-{
-       this.nextthink = time;
-       if(this.count != autocvar_g_balance_armor_blockpercent)
-       {
-               this.count = autocvar_g_balance_armor_blockpercent;
-               this.SendFlags |= 1;
-       }
-}
-
-void ClientInit_Spawn()
-{
-       entity e = new_pure(clientinit);
-       setthink(e, ClientInit_CheckUpdate);
-       Net_LinkEntity(e, false, 0, ClientInit_SendEntity);
-
-       ClientInit_CheckUpdate(e);
-}
-
-/*
-=============
-SetNewParms
-=============
-*/
-void SetNewParms ()
-{
-       // initialize parms for a new player
-       parm1 = -(86400 * 366);
-
-       MUTATOR_CALLHOOK(SetNewParms);
-}
-
-/*
-=============
-SetChangeParms
-=============
-*/
-void SetChangeParms (entity this)
-{
-       // save parms for level change
-       parm1 = this.parm_idlesince - time;
-
-       MUTATOR_CALLHOOK(SetChangeParms);
-}
-
-/*
-=============
-DecodeLevelParms
-=============
-*/
-void DecodeLevelParms(entity this)
-{
-       // load parms
-       this.parm_idlesince = parm1;
-       if (this.parm_idlesince == -(86400 * 366))
-               this.parm_idlesince = time;
-
-       // whatever happens, allow 60 seconds of idling directly after connect for map loading
-       this.parm_idlesince = max(this.parm_idlesince, time - sv_maxidle + 60);
-
-       MUTATOR_CALLHOOK(DecodeLevelParms);
-}
-
-/*
-=============
-ClientKill
-
-Called when a client types 'kill' in the console
-=============
-*/
-
-.float clientkill_nexttime;
-void ClientKill_Now_TeamChange(entity this)
-{
-       if(this.killindicator_teamchange == -1)
-       {
-               JoinBestTeam( this, false, true );
-       }
-       else if(this.killindicator_teamchange == -2)
-       {
-               if(blockSpectators)
-                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
-               PutObserverInServer(this);
-       }
-       else
-               SV_ChangeTeam(this, this.killindicator_teamchange - 1);
-       this.killindicator_teamchange = 0;
-}
-
-void ClientKill_Now(entity this)
-{
-       if(this.vehicle)
-       {
-           vehicles_exit(this.vehicle, VHEF_RELEASE);
-           if(!this.killindicator_teamchange)
-           {
-            this.vehicle_health = -1;
-            Damage(this, this, this, 1 , DEATH_KILL.m_id, this.origin, '0 0 0');
-           }
-       }
-
-       if(this.killindicator && !wasfreed(this.killindicator))
-               delete(this.killindicator);
-
-       this.killindicator = NULL;
-
-       if(this.killindicator_teamchange)
-               ClientKill_Now_TeamChange(this);
-
-       if(!IS_SPEC(this) && !IS_OBSERVER(this))
-               Damage(this, this, this, 100000, DEATH_KILL.m_id, this.origin, '0 0 0');
-
-       // now I am sure the player IS dead
-}
-void KillIndicator_Think(entity this)
-{
-       if (gameover)
-       {
-               this.owner.killindicator = NULL;
-               delete(this);
-               return;
-       }
-
-       if (this.owner.alpha < 0 && !this.owner.vehicle)
-       {
-               this.owner.killindicator = NULL;
-               delete(this);
-               return;
-       }
-
-       if(this.cnt <= 0)
-       {
-               ClientKill_Now(this.owner);
-               return;
-       }
-    else if(g_cts && this.health == 1) // health == 1 means that it's silent
-    {
-        this.nextthink = time + 1;
-        this.cnt -= 1;
-    }
-       else
-       {
-               if(this.cnt <= 10)
-                       setmodel(this, MDL_NUM(this.cnt));
-               if(IS_REAL_CLIENT(this.owner))
-               {
-                       if(this.cnt <= 10)
-                               { Send_Notification(NOTIF_ONE, this.owner, MSG_ANNCE, Announcer_PickNumber(CNT_KILL, this.cnt)); }
-               }
-               this.nextthink = time + 1;
-               this.cnt -= 1;
-       }
-}
-
-float clientkilltime;
-void ClientKill_TeamChange (entity this, float targetteam) // 0 = don't change, -1 = auto, -2 = spec
-{
-       float killtime;
-       float starttime;
-
-       if (gameover)
-               return;
-
-       killtime = autocvar_g_balance_kill_delay;
-
-       if(g_race_qualifying || g_cts)
-               killtime = 0;
-
-    if(MUTATOR_CALLHOOK(ClientKill, this, killtime))
-       return;
-
-       this.killindicator_teamchange = targetteam;
-
-    if(!this.killindicator)
-       {
-               if(!IS_DEAD(this))
-               {
-                       killtime = max(killtime, this.clientkill_nexttime - time);
-                       this.clientkill_nexttime = time + killtime + autocvar_g_balance_kill_antispam;
-               }
-
-               if(killtime <= 0 || !IS_PLAYER(this) || IS_DEAD(this))
-               {
-                       ClientKill_Now(this);
-               }
-               else
-               {
-                       starttime = max(time, clientkilltime);
-
-                       this.killindicator = spawn();
-                       this.killindicator.owner = this;
-                       this.killindicator.scale = 0.5;
-                       setattachment(this.killindicator, this, "");
-                       setorigin(this.killindicator, '0 0 52');
-                       setthink(this.killindicator, KillIndicator_Think);
-                       this.killindicator.nextthink = starttime + (this.lip) * 0.05;
-                       clientkilltime = max(clientkilltime, this.killindicator.nextthink + 0.05);
-                       this.killindicator.cnt = ceil(killtime);
-                       this.killindicator.count = bound(0, ceil(killtime), 10);
-                       //sprint(this, strcat("^1You'll be dead in ", ftos(this.killindicator.cnt), " seconds\n"));
-
-                       FOREACH_ENTITY_ENT(enemy, this,
-                       {
-                               if(it.classname != "body")
-                                       continue;
-                               it.killindicator = spawn();
-                               it.killindicator.owner = it;
-                               it.killindicator.scale = 0.5;
-                               setattachment(it.killindicator, it, "");
-                               setorigin(it.killindicator, '0 0 52');
-                               setthink(it.killindicator, KillIndicator_Think);
-                               it.killindicator.nextthink = starttime + (it.lip) * 0.05;
-                               //clientkilltime = max(clientkilltime, it.killindicator.nextthink + 0.05);
-                               it.killindicator.cnt = ceil(killtime);
-                       });
-                       this.lip = 0;
-               }
-       }
-       if(this.killindicator)
-       {
-               if(targetteam == 0) // just die
-               {
-                       this.killindicator.colormod = '0 0 0';
-                       if(IS_REAL_CLIENT(this))
-                       if(this.killindicator.cnt > 0)
-                               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_TEAMCHANGE_SUICIDE, this.killindicator.cnt);
-               }
-               else if(targetteam == -1) // auto
-               {
-                       this.killindicator.colormod = '0 1 0';
-                       if(IS_REAL_CLIENT(this))
-                       if(this.killindicator.cnt > 0)
-                               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_TEAMCHANGE_AUTO, this.killindicator.cnt);
-               }
-               else if(targetteam == -2) // spectate
-               {
-                       this.killindicator.colormod = '0.5 0.5 0.5';
-                       if(IS_REAL_CLIENT(this))
-                       if(this.killindicator.cnt > 0)
-                               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_TEAMCHANGE_SPECTATE, this.killindicator.cnt);
-               }
-               else
-               {
-                       this.killindicator.colormod = Team_ColorRGB(targetteam);
-                       if(IS_REAL_CLIENT(this))
-                       if(this.killindicator.cnt > 0)
-                               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, APP_TEAM_NUM(targetteam, CENTER_TEAMCHANGE), this.killindicator.cnt);
-               }
-       }
-
-}
-
-void ClientKill (entity this)
-{
-       if(gameover) return;
-       if(this.player_blocked) return;
-       if(STAT(FROZEN, this)) return;
-
-       ClientKill_TeamChange(this, 0);
-}
-
-void FixClientCvars(entity e)
-{
-       // send prediction settings to the client
-       stuffcmd(e, "\nin_bindmap 0 0\n");
-       if(autocvar_g_antilag == 3) // client side hitscan
-               stuffcmd(e, "cl_cmd settemp cl_prydoncursor_notrace 0\n");
-       if(autocvar_sv_gentle)
-               stuffcmd(e, "cl_cmd settemp cl_gentle 1\n");
-
-       MUTATOR_CALLHOOK(FixClientCvars, e);
-}
-
-float PlayerInIDList(entity p, string idlist)
-{
-       float n, i;
-       string s;
-
-       // NOTE: we do NOT check crypto_idfp_signed here, an unsigned ID is fine too for this
-       if (!p.crypto_idfp)
-               return 0;
-
-       // this function allows abbreviated player IDs too!
-       n = tokenize_console(idlist);
-       for(i = 0; i < n; ++i)
-       {
-               s = argv(i);
-               if(s == substring(p.crypto_idfp, 0, strlen(s)))
-                       return 1;
-       }
-
-       return 0;
-}
-
-#ifdef DP_EXT_PRECONNECT
-/*
-=============
-ClientPreConnect
-
-Called once (not at each match start) when a client begins a connection to the server
-=============
-*/
-void ClientPreConnect ()
-{ENGINE_EVENT();
-       if(autocvar_sv_eventlog)
-       {
-               GameLogEcho(sprintf(":connect:%d:%d:%s",
-                       this.playerid,
-                       etof(this),
-                       ((IS_REAL_CLIENT(this)) ? this.netaddress : "bot")
-               ));
-       }
-}
-#endif
-
-/**
-=============
-ClientConnect
-
-Called when a client connects to the server
-=============
-*/
-void ClientConnect(entity this)
-{
-       if (Ban_MaybeEnforceBanOnce(this)) return;
-       assert(!IS_CLIENT(this), return);
-       this.flags |= FL_CLIENT;
-       assert(player_count >= 0, player_count = 0);
-
-#ifdef WATERMARK
-       Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_WATERMARK, WATERMARK);
-#endif
-       this.version_nagtime = time + 10 + random() * 10;
-       TRANSMUTE(Client, this);
-
-       // identify the right forced team
-       if (autocvar_g_campaign)
-       {
-               if (IS_REAL_CLIENT(this)) // only players, not bots
-               {
-                       switch (autocvar_g_campaign_forceteam)
-                       {
-                               case 1: this.team_forced = NUM_TEAM_1; break;
-                               case 2: this.team_forced = NUM_TEAM_2; break;
-                               case 3: this.team_forced = NUM_TEAM_3; break;
-                               case 4: this.team_forced = NUM_TEAM_4; break;
-                               default: this.team_forced = 0;
-                       }
-               }
-       }
-       else if (PlayerInIDList(this, autocvar_g_forced_team_red))    this.team_forced = NUM_TEAM_1;
-       else if (PlayerInIDList(this, autocvar_g_forced_team_blue))   this.team_forced = NUM_TEAM_2;
-       else if (PlayerInIDList(this, autocvar_g_forced_team_yellow)) this.team_forced = NUM_TEAM_3;
-       else if (PlayerInIDList(this, autocvar_g_forced_team_pink))   this.team_forced = NUM_TEAM_4;
-       else switch (autocvar_g_forced_team_otherwise)
-       {
-               default: this.team_forced = 0; break;
-               case "red": this.team_forced = NUM_TEAM_1; break;
-               case "blue": this.team_forced = NUM_TEAM_2; break;
-               case "yellow": this.team_forced = NUM_TEAM_3; break;
-               case "pink": this.team_forced = NUM_TEAM_4; break;
-               case "spectate":
-               case "spectator":
-                       this.team_forced = -1;
-                       break;
-       }
-       if (!teamplay && this.team_forced > 0) this.team_forced = 0;
-
-    {
-        int id = this.playerid;
-        this.playerid = 0; // silent
-           JoinBestTeam(this, false, false); // if the team number is valid, keep it
-           this.playerid = id;
-    }
-
-       if (autocvar_sv_spectate || autocvar_g_campaign || this.team_forced < 0) {
-               TRANSMUTE(Observer, this);
-       } else {
-               if (!teamplay || autocvar_g_balance_teams) {
-                       TRANSMUTE(Player, this);
-                       campaign_bots_may_start = true;
-               } else {
-                       TRANSMUTE(Observer, this); // do it anyway
-               }
-       }
-
-       PlayerStats_GameReport_AddEvent(sprintf("kills-%d", this.playerid));
-
-       // always track bots, don't ask for cl_allow_uidtracking
-    if (IS_BOT_CLIENT(this)) PlayerStats_GameReport_AddPlayer(this);
-
-       if (autocvar_sv_eventlog)
-               GameLogEcho(strcat(":join:", ftos(this.playerid), ":", ftos(etof(this)), ":", ((IS_REAL_CLIENT(this)) ? this.netaddress : "bot"), ":", this.netname));
-
-       LogTeamchange(this.playerid, this.team, 1);
-
-       this.just_joined = true;  // stop spamming the eventlog with additional lines when the client connects
-
-       this.netname_previous = strzone(this.netname);
-
-       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((teamplay && IS_PLAYER(this)) ? APP_TEAM_ENT(this, INFO_JOIN_CONNECT_TEAM) : INFO_JOIN_CONNECT), this.netname);
-
-       stuffcmd(this, clientstuff, "\n");
-       stuffcmd(this, "cl_particles_reloadeffects\n"); // TODO do we still need this?
-
-       FixClientCvars(this);
-
-       // get version info from player
-       stuffcmd(this, "cmd clientversion $gameversion\n");
-
-       // notify about available teams
-       if (teamplay)
-       {
-               CheckAllowedTeams(this);
-               int t = 0;
-               if (c1 >= 0) t |= BIT(0);
-               if (c2 >= 0) t |= BIT(1);
-               if (c3 >= 0) t |= BIT(2);
-               if (c4 >= 0) t |= BIT(3);
-               stuffcmd(this, sprintf("set _teams_available %d\n", t));
-       }
-       else
-       {
-               stuffcmd(this, "set _teams_available 0\n");
-       }
-
-       bot_relinkplayerlist();
-
-       this.spectatortime = time;
-       if (blockSpectators)
-       {
-               Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
-       }
-
-       this.jointime = time;
-       this.allowed_timeouts = autocvar_sv_timeout_number;
-
-       if (IS_REAL_CLIENT(this))
-       {
-               if (!autocvar_g_campaign)
-               {
-                       this.motd_actived_time = -1;
-                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, getwelcomemessage(this));
-               }
-
-               if (g_weaponarena_weapons == WEPSET(TUBA))
-                       stuffcmd(this, "cl_cmd settemp chase_active 1\n");
-       }
-
-       if (!sv_foginterval && world.fog != "")
-               stuffcmd(this, strcat("\nfog ", world.fog, "\nr_fog_exp2 0\nr_drawfog 1\n"));
-
-       if (autocvar_sv_teamnagger && !(autocvar_bot_vs_human && AvailableTeams() == 2))
-               if (!g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts
-                       send_CSQC_teamnagger();
-
-       CSQCMODEL_AUTOINIT(this);
-
-       this.model_randomizer = random();
-
-       if (IS_REAL_CLIENT(this))
-               sv_notice_join(this);
-
-       FOREACH_ENTITY_FLOAT(init_for_player_needed, true, {
-               it.init_for_player(it, this);
-       });
-
-       MUTATOR_CALLHOOK(ClientConnect, this);
-}
-/*
-=============
-ClientDisconnect
-
-Called when a client disconnects from the server
-=============
-*/
-.entity chatbubbleentity;
-void ReadyCount();
-void ClientDisconnect(entity this)
-{
-       assert(IS_CLIENT(this), return);
-
-       PlayerStats_GameReport_FinalizePlayer(this);
-       if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE);
-       if (this.active_minigame) part_minigame(this);
-       if (IS_PLAYER(this)) Send_Effect(EFFECT_SPAWN_NEUTRAL, this.origin, '0 0 0', 1);
-
-       if (autocvar_sv_eventlog)
-               GameLogEcho(strcat(":part:", ftos(this.playerid)));
-
-       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_DISCONNECT, this.netname);
-
-       SetSpectatee(this, NULL);
-
-    MUTATOR_CALLHOOK(ClientDisconnect, this);
-
-       ClientState_detach(this);
-
-       Portal_ClearAll(this);
-
-       Unfreeze(this);
-
-       RemoveGrapplingHook(this);
-
-       // Here, everything has been done that requires this player to be a client.
-
-       this.flags &= ~FL_CLIENT;
-
-       if (this.chatbubbleentity) delete(this.chatbubbleentity);
-       if (this.killindicator) delete(this.killindicator);
-
-       WaypointSprite_PlayerGone(this);
-
-       bot_relinkplayerlist();
-
-       if (this.netname_previous) strunzone(this.netname_previous);
-       if (this.clientstatus) strunzone(this.clientstatus);
-       if (this.weaponorder_byimpulse) strunzone(this.weaponorder_byimpulse);
-       if (this.personal) delete(this.personal);
-
-       this.playerid = 0;
-       ReadyCount();
-       if (vote_called && IS_REAL_CLIENT(this)) VoteCount(false);
-}
-
-void ChatBubbleThink(entity this)
-{
-       this.nextthink = time;
-       if ((this.owner.alpha < 0) || this.owner.chatbubbleentity != this)
-       {
-               if(this.owner) // but why can that ever be NULL?
-                       this.owner.chatbubbleentity = NULL;
-               delete(this);
-               return;
-       }
-
-       this.mdl = "";
-
-       if ( !IS_DEAD(this.owner) && IS_PLAYER(this.owner) )
-       {
-               if ( this.owner.active_minigame )
-                       this.mdl = "models/sprites/minigame_busy.iqm";
-               else if (PHYS_INPUT_BUTTON_CHAT(this.owner))
-                       this.mdl = "models/misc/chatbubble.spr";
-       }
-
-       if ( this.model != this.mdl )
-               _setmodel(this, this.mdl);
-
-}
-
-void UpdateChatBubble(entity this)
-{
-       if (this.alpha < 0)
-               return;
-       // spawn a chatbubble entity if needed
-       if (!this.chatbubbleentity)
-       {
-               this.chatbubbleentity = new(chatbubbleentity);
-               this.chatbubbleentity.owner = this;
-               this.chatbubbleentity.exteriormodeltoclient = this;
-               setthink(this.chatbubbleentity, ChatBubbleThink);
-               this.chatbubbleentity.nextthink = time;
-               setmodel(this.chatbubbleentity, MDL_CHAT); // precision set below
-               //setorigin(this.chatbubbleentity, this.origin + '0 0 15' + this.maxs_z * '0 0 1');
-               setorigin(this.chatbubbleentity, '0 0 15' + this.maxs_z * '0 0 1');
-               setattachment(this.chatbubbleentity, this, "");  // sticks to moving player better, also conserves bandwidth
-               this.chatbubbleentity.mdl = this.chatbubbleentity.model;
-               //this.chatbubbleentity.model = "";
-               this.chatbubbleentity.effects = EF_LOWPRECISION;
-       }
-}
-
-
-// LordHavoc: this hack will be removed when proper _pants/_shirt layers are
-// added to the model skins
-/*void UpdateColorModHack()
-{
-       float c;
-       c = this.clientcolors & 15;
-       // LordHavoc: only bothering to support white, green, red, yellow, blue
-            if (!teamplay) this.colormod = '0 0 0';
-       else if (c ==  0) this.colormod = '1.00 1.00 1.00';
-       else if (c ==  3) this.colormod = '0.10 1.73 0.10';
-       else if (c ==  4) this.colormod = '1.73 0.10 0.10';
-       else if (c == 12) this.colormod = '1.22 1.22 0.10';
-       else if (c == 13) this.colormod = '0.10 0.10 1.73';
-       else this.colormod = '1 1 1';
-}*/
-
-void respawn(entity this)
-{
-       if(this.alpha >= 0 && autocvar_g_respawn_ghosts)
-       {
-               this.solid = SOLID_NOT;
-               this.takedamage = DAMAGE_NO;
-               set_movetype(this, MOVETYPE_FLY);
-               this.velocity = '0 0 1' * autocvar_g_respawn_ghosts_speed;
-               this.avelocity = randomvec() * autocvar_g_respawn_ghosts_speed * 3 - randomvec() * autocvar_g_respawn_ghosts_speed * 3;
-               this.effects |= CSQCMODEL_EF_RESPAWNGHOST;
-               Send_Effect(EFFECT_RESPAWN_GHOST, this.origin, '0 0 0', 1);
-               if(autocvar_g_respawn_ghosts_maxtime)
-                       SUB_SetFade (this, time + autocvar_g_respawn_ghosts_maxtime / 2 + random () * (autocvar_g_respawn_ghosts_maxtime - autocvar_g_respawn_ghosts_maxtime / 2), 1.5);
-       }
-
-       CopyBody(this, 1);
-
-       this.effects |= EF_NODRAW; // prevent another CopyBody
-       PutClientInServer(this);
-}
-
-void play_countdown(entity this, float finished, Sound samp)
-{
-    TC(Sound, samp);
-       if(IS_REAL_CLIENT(this))
-               if(floor(finished - time - frametime) != floor(finished - time))
-                       if(finished - time < 6)
-                               sound (this, CH_INFO, samp, VOL_BASE, ATTEN_NORM);
-}
-
-void player_powerups(entity this)
-{
-       // add a way to see what the items were BEFORE all of these checks for the mutator hook
-       int items_prev = this.items;
-
-       if((this.items & IT_USING_JETPACK) && !IS_DEAD(this) && !gameover)
-               this.modelflags |= MF_ROCKET;
-       else
-               this.modelflags &= ~MF_ROCKET;
-
-       this.effects &= ~(EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT | EF_FLAME | EF_NODEPTHTEST);
-
-       if((this.alpha < 0 || IS_DEAD(this)) && !this.vehicle) // don't apply the flags if the player is gibbed
-               return;
-
-       Fire_ApplyDamage(this);
-       Fire_ApplyEffect(this);
-
-       if (!g_instagib)
-       {
-               if (this.items & ITEM_Strength.m_itemid)
-               {
-                       play_countdown(this, this.strength_finished, SND_POWEROFF);
-                       this.effects = this.effects | (EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT);
-                       if (time > this.strength_finished)
-                       {
-                               this.items = this.items - (this.items & ITEM_Strength.m_itemid);
-                               //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERDOWN_STRENGTH, this.netname);
-                               Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERDOWN_STRENGTH);
-                       }
-               }
-               else
-               {
-                       if (time < this.strength_finished)
-                       {
-                               this.items = this.items | ITEM_Strength.m_itemid;
-                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_STRENGTH, this.netname);
-                               Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERUP_STRENGTH);
-                       }
-               }
-               if (this.items & ITEM_Shield.m_itemid)
-               {
-                       play_countdown(this, this.invincible_finished, SND_POWEROFF);
-                       this.effects = this.effects | (EF_RED | EF_ADDITIVE | EF_FULLBRIGHT);
-                       if (time > this.invincible_finished)
-                       {
-                               this.items = this.items - (this.items & ITEM_Shield.m_itemid);
-                               //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERDOWN_SHIELD, this.netname);
-                               Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERDOWN_SHIELD);
-                       }
-               }
-               else
-               {
-                       if (time < this.invincible_finished)
-                       {
-                               this.items = this.items | ITEM_Shield.m_itemid;
-                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_SHIELD, this.netname);
-                               Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERUP_SHIELD);
-                       }
-               }
-               if (this.items & IT_SUPERWEAPON)
-               {
-                       if (!(this.weapons & WEPSET_SUPERWEAPONS))
-                       {
-                               this.superweapons_finished = 0;
-                               this.items = this.items - (this.items & IT_SUPERWEAPON);
-                               //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_LOST, this.netname);
-                               Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_SUPERWEAPON_LOST);
-                       }
-                       else if (this.items & IT_UNLIMITED_SUPERWEAPONS)
-                       {
-                               // don't let them run out
-                       }
-                       else
-                       {
-                               play_countdown(this, this.superweapons_finished, SND_POWEROFF);
-                               if (time > this.superweapons_finished)
-                               {
-                                       this.items = this.items - (this.items & IT_SUPERWEAPON);
-                                       this.weapons &= ~WEPSET_SUPERWEAPONS;
-                                       //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_BROKEN, this.netname);
-                                       Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_SUPERWEAPON_BROKEN);
-                               }
-                       }
-               }
-               else if(this.weapons & WEPSET_SUPERWEAPONS)
-               {
-                       if (time < this.superweapons_finished || (this.items & IT_UNLIMITED_SUPERWEAPONS))
-                       {
-                               this.items = this.items | IT_SUPERWEAPON;
-                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_PICKUP, this.netname);
-                               Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_SUPERWEAPON_PICKUP);
-                       }
-                       else
-                       {
-                               this.superweapons_finished = 0;
-                               this.weapons &= ~WEPSET_SUPERWEAPONS;
-                       }
-               }
-               else
-               {
-                       this.superweapons_finished = 0;
-               }
-       }
-
-       if(autocvar_g_nodepthtestplayers)
-               this.effects = this.effects | EF_NODEPTHTEST;
-
-       if(autocvar_g_fullbrightplayers)
-               this.effects = this.effects | EF_FULLBRIGHT;
-
-       if (time >= game_starttime)
-       if (time < this.spawnshieldtime)
-               this.effects = this.effects | (EF_ADDITIVE | EF_FULLBRIGHT);
-
-       MUTATOR_CALLHOOK(PlayerPowerups, this, items_prev);
-}
-
-float CalcRegen(float current, float stable, float regenfactor, float regenframetime)
-{
-       if(current > stable)
-               return current;
-       else if(current > stable - 0.25) // when close enough, "snap"
-               return stable;
-       else
-               return min(stable, current + (stable - current) * regenfactor * regenframetime);
-}
-
-float CalcRot(float current, float stable, float rotfactor, float rotframetime)
-{
-       if(current < stable)
-               return current;
-       else if(current < stable + 0.25) // when close enough, "snap"
-               return stable;
-       else
-               return max(stable, current + (stable - current) * rotfactor * rotframetime);
-}
-
-float CalcRotRegen(float current, float regenstable, float regenfactor, float regenlinear, float regenframetime, float rotstable, float rotfactor, float rotlinear, float rotframetime, float limit)
-{
-       if(current > rotstable)
-       {
-               if(rotframetime > 0)
-               {
-                       current = CalcRot(current, rotstable, rotfactor, rotframetime);
-                       current = max(rotstable, current - rotlinear * rotframetime);
-               }
-       }
-       else if(current < regenstable)
-       {
-               if(regenframetime > 0)
-               {
-                       current = CalcRegen(current, regenstable, regenfactor, regenframetime);
-                       current = min(regenstable, current + regenlinear * regenframetime);
-               }
-       }
-
-       if(current > limit)
-               current = limit;
-
-       return current;
-}
-
-void player_regen(entity this)
-{
-       float max_mod, regen_mod, rot_mod, limit_mod;
-       max_mod = regen_mod = rot_mod = limit_mod = 1;
-
-       float regen_health = autocvar_g_balance_health_regen;
-       float regen_health_linear = autocvar_g_balance_health_regenlinear;
-       float regen_health_rot = autocvar_g_balance_health_rot;
-       float regen_health_rotlinear = autocvar_g_balance_health_rotlinear;
-       float regen_health_stable = autocvar_g_balance_health_regenstable;
-       float regen_health_rotstable = autocvar_g_balance_health_rotstable;
-       bool mutator_returnvalue = MUTATOR_CALLHOOK(PlayerRegen, this, max_mod, regen_mod, rot_mod, limit_mod, regen_health, regen_health_linear, regen_health_rot,
-               regen_health_rotlinear, regen_health_stable, regen_health_rotstable);
-       max_mod = M_ARGV(1, float);
-       regen_mod = M_ARGV(2, float);
-       rot_mod = M_ARGV(3, float);
-       limit_mod = M_ARGV(4, float);
-       regen_health = M_ARGV(5, float);
-       regen_health_linear = M_ARGV(6, float);
-       regen_health_rot = M_ARGV(7, float);
-       regen_health_rotlinear = M_ARGV(8, float);
-       regen_health_stable = M_ARGV(9, float);
-       regen_health_rotstable = M_ARGV(10, float);
-
-
-       if(!mutator_returnvalue)
-       if(!STAT(FROZEN, this))
-       {
-               float mina, maxa, limith, limita;
-               maxa = autocvar_g_balance_armor_rotstable;
-               mina = autocvar_g_balance_armor_regenstable;
-               limith = autocvar_g_balance_health_limit;
-               limita = autocvar_g_balance_armor_limit;
-
-               regen_health_rotstable = regen_health_rotstable * max_mod;
-               regen_health_stable = regen_health_stable * max_mod;
-               limith = limith * limit_mod;
-               limita = limita * limit_mod;
-
-               this.armorvalue = CalcRotRegen(this.armorvalue, mina, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear, regen_mod * frametime * (time > this.pauseregen_finished), maxa, autocvar_g_balance_armor_rot, autocvar_g_balance_armor_rotlinear, rot_mod * frametime * (time > this.pauserotarmor_finished), limita);
-               this.health = CalcRotRegen(this.health, regen_health_stable, regen_health, regen_health_linear, regen_mod * frametime * (time > this.pauseregen_finished), regen_health_rotstable, regen_health_rot, regen_health_rotlinear, rot_mod * frametime * (time > this.pauserothealth_finished), limith);
-       }
-
-       // if player rotted to death...  die!
-       // check this outside above checks, as player may still be able to rot to death
-       if(this.health < 1)
-       {
-               if(this.vehicle)
-                       vehicles_exit(this.vehicle, VHEF_RELEASE);
-               if(this.event_damage)
-                       this.event_damage(this, this, this, 1, DEATH_ROT.m_id, this.origin, '0 0 0');
-       }
-
-       if (!(this.items & IT_UNLIMITED_WEAPON_AMMO))
-       {
-               float minf, maxf, limitf;
-
-               maxf = autocvar_g_balance_fuel_rotstable;
-               minf = autocvar_g_balance_fuel_regenstable;
-               limitf = autocvar_g_balance_fuel_limit;
-
-               this.ammo_fuel = CalcRotRegen(this.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, frametime * (time > this.pauseregen_finished) * ((this.items & ITEM_JetpackRegen.m_itemid) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > this.pauserotfuel_finished), limitf);
-       }
-}
-
-bool zoomstate_set;
-void SetZoomState(entity this, float z)
-{
-       if(z != this.zoomstate)
-       {
-               this.zoomstate = z;
-               ClientData_Touch(this);
-       }
-       zoomstate_set = true;
-}
-
-void GetPressedKeys(entity this)
-{
-       MUTATOR_CALLHOOK(GetPressedKeys, this);
-       int keys = this.pressedkeys;
-       keys = BITSET(keys, KEY_FORWARD,        this.movement.x > 0);
-       keys = BITSET(keys, KEY_BACKWARD,       this.movement.x < 0);
-       keys = BITSET(keys, KEY_RIGHT,          this.movement.y > 0);
-       keys = BITSET(keys, KEY_LEFT,           this.movement.y < 0);
-
-       keys = BITSET(keys, KEY_JUMP,           PHYS_INPUT_BUTTON_JUMP(this));
-       keys = BITSET(keys, KEY_CROUCH,         PHYS_INPUT_BUTTON_CROUCH(this));
-       keys = BITSET(keys, KEY_ATCK,           PHYS_INPUT_BUTTON_ATCK(this));
-       keys = BITSET(keys, KEY_ATCK2,          PHYS_INPUT_BUTTON_ATCK2(this));
-       this.pressedkeys = keys;
-}
-
-/*
-======================
-spectate mode routines
-======================
-*/
-
-void SpectateCopy(entity this, entity spectatee)
-{
-    TC(Client, this); TC(Client, spectatee);
-
-       MUTATOR_CALLHOOK(SpectateCopy, spectatee, this);
-       PS(this) = PS(spectatee);
-       this.armortype = spectatee.armortype;
-       this.armorvalue = spectatee.armorvalue;
-       this.ammo_cells = spectatee.ammo_cells;
-       this.ammo_plasma = spectatee.ammo_plasma;
-       this.ammo_shells = spectatee.ammo_shells;
-       this.ammo_nails = spectatee.ammo_nails;
-       this.ammo_rockets = spectatee.ammo_rockets;
-       this.ammo_fuel = spectatee.ammo_fuel;
-       this.clip_load = spectatee.clip_load;
-       this.clip_size = spectatee.clip_size;
-       this.effects = spectatee.effects & EFMASK_CHEAP; // eat performance
-       this.health = spectatee.health;
-       this.impulse = 0;
-       this.items = spectatee.items;
-       this.last_pickup = spectatee.last_pickup;
-       this.hit_time = spectatee.hit_time;
-       this.strength_finished = spectatee.strength_finished;
-       this.invincible_finished = spectatee.invincible_finished;
-       this.pressedkeys = spectatee.pressedkeys;
-       this.weapons = spectatee.weapons;
-       this.vortex_charge = spectatee.vortex_charge;
-       this.vortex_chargepool_ammo = spectatee.vortex_chargepool_ammo;
-       this.hagar_load = spectatee.hagar_load;
-       this.arc_heat_percent = spectatee.arc_heat_percent;
-       this.minelayer_mines = spectatee.minelayer_mines;
-       this.punchangle = spectatee.punchangle;
-       this.view_ofs = spectatee.view_ofs;
-       this.velocity = spectatee.velocity;
-       this.dmg_take = spectatee.dmg_take;
-       this.dmg_save = spectatee.dmg_save;
-       this.dmg_inflictor = spectatee.dmg_inflictor;
-       this.v_angle = spectatee.v_angle;
-       this.angles = spectatee.v_angle;
-       STAT(FROZEN, this) = STAT(FROZEN, spectatee);
-       this.revive_progress = spectatee.revive_progress;
-       if(!PHYS_INPUT_BUTTON_USE(this) && STAT(CAMERA_SPECTATOR, this) != 2)
-               this.fixangle = true;
-       setorigin(this, spectatee.origin);
-       setsize(this, spectatee.mins, spectatee.maxs);
-       SetZoomState(this, spectatee.zoomstate);
-
-    anticheat_spectatecopy(this, spectatee);
-       this.hud = spectatee.hud;
-       if(spectatee.vehicle)
-    {
-       this.angles = spectatee.v_angle;
-
-        //this.fixangle = false;
-        //this.velocity = spectatee.vehicle.velocity;
-        this.vehicle_health = spectatee.vehicle_health;
-        this.vehicle_shield = spectatee.vehicle_shield;
-        this.vehicle_energy = spectatee.vehicle_energy;
-        this.vehicle_ammo1 = spectatee.vehicle_ammo1;
-        this.vehicle_ammo2 = spectatee.vehicle_ammo2;
-        this.vehicle_reload1 = spectatee.vehicle_reload1;
-        this.vehicle_reload2 = spectatee.vehicle_reload2;
-
-        //msg_entity = this;
-
-       // WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
-            //WriteAngle(MSG_ONE,  spectatee.v_angle.x);
-           // WriteAngle(MSG_ONE,  spectatee.v_angle.y);
-           // WriteAngle(MSG_ONE,  spectatee.v_angle.z);
-
-        //WriteByte (MSG_ONE, SVC_SETVIEW);
-        //    WriteEntity(MSG_ONE, this);
-        //makevectors(spectatee.v_angle);
-        //setorigin(this, spectatee.origin - v_forward * 400 + v_up * 300);*/
-    }
-}
-
-bool SpectateUpdate(entity this)
-{
-       if(!this.enemy)
-           return false;
-
-       if(!IS_PLAYER(this.enemy) || this == this.enemy)
-       {
-               SetSpectatee(this, NULL);
-               return false;
-       }
-
-       SpectateCopy(this, this.enemy);
-
-       return true;
-}
-
-bool SpectateSet(entity this)
-{
-       if(!IS_PLAYER(this.enemy))
-               return false;
-
-       ClientData_Touch(this.enemy);
-
-       msg_entity = this;
-       WriteByte(MSG_ONE, SVC_SETVIEW);
-       WriteEntity(MSG_ONE, this.enemy);
-       set_movetype(this, MOVETYPE_NONE);
-       accuracy_resend(this);
-
-       if(!SpectateUpdate(this))
-               PutObserverInServer(this);
-
-       return true;
-}
-
-void SetSpectatee(entity this, entity spectatee)
-{
-       entity old_spectatee = this.enemy;
-
-       this.enemy = spectatee;
-
-       // WEAPONTODO
-       // these are required to fix the spectator bug with arc
-       if(old_spectatee)
-       {
-               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-               {
-                       .entity weaponentity = weaponentities[slot];
-                       if(old_spectatee.(weaponentity).arc_beam)
-                               old_spectatee.(weaponentity).arc_beam.SendFlags |= ARC_SF_SETTINGS;
-               }
-       }
-       if(this.enemy)
-       {
-               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-               {
-                       .entity weaponentity = weaponentities[slot];
-                       if(this.enemy.(weaponentity).arc_beam)
-                               this.enemy.(weaponentity).arc_beam.SendFlags |= ARC_SF_SETTINGS;
-               }
-       }
-
-       // needed to update spectator list
-       if(old_spectatee) { ClientData_Touch(old_spectatee); }
-}
-
-bool Spectate(entity this, entity pl)
-{
-       if(MUTATOR_CALLHOOK(SpectateSet, this, pl))
-               return false;
-       pl = M_ARGV(1, entity);
-
-       SetSpectatee(this, pl);
-       return SpectateSet(this);
-}
-
-bool SpectateNext(entity this)
-{
-       entity ent = find(this.enemy, classname, STR_PLAYER);
-
-       if (MUTATOR_CALLHOOK(SpectateNext, this, ent))
-               ent = M_ARGV(1, entity);
-       else if (!ent)
-               ent = find(ent, classname, STR_PLAYER);
-
-       if(ent) { SetSpectatee(this, ent); }
-
-       return SpectateSet(this);
-}
-
-bool SpectatePrev(entity this)
-{
-       // NOTE: chain order is from the highest to the lower entnum (unlike find)
-       entity ent = findchain(classname, STR_PLAYER);
-       if (!ent) // no player
-               return false;
-
-       entity first = ent;
-       // skip players until current spectated player
-       if(this.enemy)
-       while(ent && ent != this.enemy)
-               ent = ent.chain;
-
-       switch (MUTATOR_CALLHOOK(SpectatePrev, this, ent, first))
-       {
-               case MUT_SPECPREV_FOUND:
-                   ent = M_ARGV(1, entity);
-                   break;
-               case MUT_SPECPREV_RETURN:
-                   return true;
-               case MUT_SPECPREV_CONTINUE:
-               default:
-               {
-                       if(ent.chain)
-                               ent = ent.chain;
-                       else
-                               ent = first;
-                       break;
-               }
-       }
-
-       SetSpectatee(this, ent);
-       return SpectateSet(this);
-}
-
-/*
-=============
-ShowRespawnCountdown()
-
-Update a respawn countdown display.
-=============
-*/
-void ShowRespawnCountdown(entity this)
-{
-       float number;
-       if(!IS_DEAD(this)) // just respawned?
-               return;
-       else
-       {
-               number = ceil(this.respawn_time - time);
-               if(number <= 0)
-                       return;
-               if(number <= this.respawn_countdown)
-               {
-                       this.respawn_countdown = number - 1;
-                       if(ceil(this.respawn_time - (time + 0.5)) == number) // only say it if it is the same number even in 0.5s; to prevent overlapping sounds
-                               { Send_Notification(NOTIF_ONE, this, MSG_ANNCE, Announcer_PickNumber(CNT_RESPAWN, number)); }
-               }
-       }
-}
-
-void LeaveSpectatorMode(entity this)
-{
-       if(this.caplayer)
-               return;
-       if(nJoinAllowed(this, this))
-       {
-               if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (this.wasplayer && autocvar_g_changeteam_banned) || this.team_forced > 0)
-               {
-                       TRANSMUTE(Player, this);
-
-                       SetSpectatee(this, NULL);
-
-                       if(autocvar_g_campaign || autocvar_g_balance_teams)
-                               { JoinBestTeam(this, false, true); }
-
-                       if(autocvar_g_campaign)
-                               { campaign_bots_may_start = true; }
-
-                       Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_PREVENT_JOIN);
-
-                       PutClientInServer(this);
-
-                       if(IS_PLAYER(this)) { Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((teamplay && this.team != -1) ? APP_TEAM_ENT(this, INFO_JOIN_PLAY_TEAM) : INFO_JOIN_PLAY), this.netname); }
-               }
-               else
-                       stuffcmd(this, "menu_showteamselect\n");
-       }
-       else
-       {
-               // Player may not join because g_maxplayers is set
-               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_PREVENT);
-       }
-}
-
-/**
- * Determines whether the player is allowed to join. This depends on cvar
- * g_maxplayers, if it isn't used this function always return true, otherwise
- * it checks whether the number of currently playing players exceeds g_maxplayers.
- * @return int number of free slots for players, 0 if none
- */
-bool nJoinAllowed(entity this, entity ignore)
-{
-       if(!ignore)
-       // this is called that way when checking if anyone may be able to join (to build qcstatus)
-       // so report 0 free slots if restricted
-       {
-               if(autocvar_g_forced_team_otherwise == "spectate")
-                       return false;
-               if(autocvar_g_forced_team_otherwise == "spectator")
-                       return false;
-       }
-
-       if(this.team_forced < 0)
-               return false; // forced spectators can never join
-
-       // TODO simplify this
-       int totalClients = 0;
-       int currentlyPlaying = 0;
-       FOREACH_CLIENT(true, LAMBDA(
-               if(it != ignore)
-                       ++totalClients;
-               if(IS_REAL_CLIENT(it))
-               if(IS_PLAYER(it) || it.caplayer)
-                       ++currentlyPlaying;
-       ));
-
-       if (!autocvar_g_maxplayers)
-               return maxclients - totalClients;
-
-       if(currentlyPlaying < autocvar_g_maxplayers)
-               return min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying);
-
-       return false;
-}
-
-/**
- * Checks whether the client is an observer or spectator, if so, he will get kicked after
- * g_maxplayers_spectator_blocktime seconds
- */
-void checkSpectatorBlock(entity this)
-{
-       if(IS_SPEC(this) || IS_OBSERVER(this))
-       if(!this.caplayer)
-       if(IS_REAL_CLIENT(this))
-       {
-               if( time > (this.spectatortime + autocvar_g_maxplayers_spectator_blocktime) ) {
-                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_QUIT_KICK_SPECTATING);
-                       dropclient(this);
-               }
-       }
-}
-
-void PrintWelcomeMessage(entity this)
-{
-       if(this.motd_actived_time == 0)
-       {
-               if (autocvar_g_campaign) {
-                       if ((IS_PLAYER(this) && PHYS_INPUT_BUTTON_INFO(this)) || (!IS_PLAYER(this))) {
-                               this.motd_actived_time = time;
-                               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, campaign_message);
-                       }
-               } else {
-                       if (PHYS_INPUT_BUTTON_INFO(this)) {
-                               this.motd_actived_time = time;
-                               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, getwelcomemessage(this));
-                       }
-               }
-       }
-       else if(this.motd_actived_time > 0) // showing MOTD or campaign message
-       {
-               if (autocvar_g_campaign) {
-                       if (PHYS_INPUT_BUTTON_INFO(this))
-                               this.motd_actived_time = time;
-                       else if ((time - this.motd_actived_time > 2) && IS_PLAYER(this)) { // hide it some seconds after BUTTON_INFO has been released
-                               this.motd_actived_time = 0;
-                               Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_MOTD);
-                       }
-               } else {
-                       if (PHYS_INPUT_BUTTON_INFO(this))
-                               this.motd_actived_time = time;
-                       else if (time - this.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released
-                               this.motd_actived_time = 0;
-                               Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_MOTD);
-                       }
-               }
-       }
-       else //if(this.motd_actived_time < 0) // just connected, motd is active
-       {
-               if(PHYS_INPUT_BUTTON_INFO(this)) // BUTTON_INFO hides initial MOTD
-                       this.motd_actived_time = -2; // wait until BUTTON_INFO gets released
-               else if(this.motd_actived_time == -2 || IS_PLAYER(this) || IS_SPEC(this))
-               {
-                       // instanctly hide MOTD
-                       this.motd_actived_time = 0;
-                       Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_MOTD);
-               }
-       }
-}
-
-void ObserverThink(entity this)
-{
-       if ( this.impulse )
-       {
-               MinigameImpulse(this, this.impulse);
-               this.impulse = 0;
-       }
-       if (this.flags & FL_JUMPRELEASED) {
-               if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) {
-                       this.flags &= ~FL_JUMPRELEASED;
-                       this.flags |= FL_SPAWNING;
-               } else if(PHYS_INPUT_BUTTON_ATCK(this) && !this.version_mismatch) {
-                       this.flags &= ~FL_JUMPRELEASED;
-                       if(SpectateNext(this)) {
-                               TRANSMUTE(Spectator, this);
-                       }
-               } else {
-                       int preferred_movetype = ((!PHYS_INPUT_BUTTON_USE(this) ? this.cvar_cl_clippedspectating : !this.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP);
-                       set_movetype(this, preferred_movetype);
-               }
-       } else {
-               if (!(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this))) {
-                       this.flags |= FL_JUMPRELEASED;
-                       if(this.flags & FL_SPAWNING)
-                       {
-                               this.flags &= ~FL_SPAWNING;
-                               LeaveSpectatorMode(this);
-                               return;
-                       }
-               }
-       }
-}
-
-void SpectatorThink(entity this)
-{
-       if ( this.impulse )
-       {
-               if(MinigameImpulse(this, this.impulse))
-                       this.impulse = 0;
-
-               if (this.impulse == IMP_weapon_drop.impulse)
-               {
-                       STAT(CAMERA_SPECTATOR, this) = (STAT(CAMERA_SPECTATOR, this) + 1) % 3;
-                       this.impulse = 0;
-                       return;
-               }
-       }
-       if (this.flags & FL_JUMPRELEASED) {
-               if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) {
-                       this.flags &= ~FL_JUMPRELEASED;
-                       this.flags |= FL_SPAWNING;
-               } else if(PHYS_INPUT_BUTTON_ATCK(this) || this.impulse == 10 || this.impulse == 15 || this.impulse == 18 || (this.impulse >= 200 && this.impulse <= 209)) {
-                       this.flags &= ~FL_JUMPRELEASED;
-                       if(SpectateNext(this)) {
-                               TRANSMUTE(Spectator, this);
-                       } else {
-                               TRANSMUTE(Observer, this);
-                               PutClientInServer(this);
-                       }
-                       this.impulse = 0;
-               } else if(this.impulse == 12 || this.impulse == 16  || this.impulse == 19 || (this.impulse >= 220 && this.impulse <= 229)) {
-                       this.flags &= ~FL_JUMPRELEASED;
-                       if(SpectatePrev(this)) {
-                               TRANSMUTE(Spectator, this);
-                       } else {
-                               TRANSMUTE(Observer, this);
-                               PutClientInServer(this);
-                       }
-                       this.impulse = 0;
-               } else if (PHYS_INPUT_BUTTON_ATCK2(this)) {
-                       this.flags &= ~FL_JUMPRELEASED;
-                       TRANSMUTE(Observer, this);
-                       PutClientInServer(this);
-               } else {
-                       if(!SpectateUpdate(this))
-                               PutObserverInServer(this);
-               }
-       } else {
-               if (!(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this))) {
-                       this.flags |= FL_JUMPRELEASED;
-                       if(this.flags & FL_SPAWNING)
-                       {
-                               this.flags &= ~FL_SPAWNING;
-                               LeaveSpectatorMode(this);
-                               return;
-                       }
-               }
-               if(!SpectateUpdate(this))
-                       PutObserverInServer(this);
-       }
-
-       this.flags |= FL_CLIENT | FL_NOTARGET;
-}
-
-void vehicles_enter (entity pl, entity veh);
-void PlayerUseKey(entity this)
-{
-       if (!IS_PLAYER(this))
-               return;
-
-       if(this.vehicle)
-       {
-               if(!gameover)
-               {
-                       vehicles_exit(this.vehicle, VHEF_NORMAL);
-                       return;
-               }
-       }
-       else if(autocvar_g_vehicles_enter)
-       {
-               if(!STAT(FROZEN, this))
-               if(!IS_DEAD(this))
-               if(!gameover)
-               {
-                       entity head, closest_target = NULL;
-                       head = WarpZone_FindRadius(this.origin, autocvar_g_vehicles_enter_radius, true);
-
-                       while(head) // find the closest acceptable target to enter
-                       {
-                               if(IS_VEHICLE(head))
-                               if(!IS_DEAD(head))
-                               if(!head.owner || ((head.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(head.owner, this)))
-                               if(head.takedamage != DAMAGE_NO)
-                               {
-                                       if(closest_target)
-                                       {
-                                               if(vlen2(this.origin - head.origin) < vlen2(this.origin - closest_target.origin))
-                                               { closest_target = head; }
-                                       }
-                                       else { closest_target = head; }
-                               }
-
-                               head = head.chain;
-                       }
-
-                       if(closest_target) { vehicles_enter(this, closest_target); return; }
-               }
-       }
-
-       // a use key was pressed; call handlers
-       MUTATOR_CALLHOOK(PlayerUseKey, this);
-}
-
-
-/*
-=============
-PlayerPreThink
-
-Called every frame for each client before the physics are run
-=============
-*/
-.float usekeypressed;
-.float last_vehiclecheck;
-.int items_added;
-void PlayerPreThink (entity this)
-{
-       WarpZone_PlayerPhysics_FixVAngle(this);
-
-    STAT(GAMESTARTTIME, this) = game_starttime;
-       STAT(ROUNDSTARTTIME, this) = round_starttime;
-       STAT(ALLOW_OLDVORTEXBEAM, this) = autocvar_g_allow_oldvortexbeam;
-       STAT(LEADLIMIT, this) = autocvar_leadlimit;
-
-       STAT(WEAPONSINMAP, this) = weaponsInMap;
-
-       if (frametime) {
-               // physics frames: update anticheat stuff
-               anticheat_prethink(this);
-       }
-
-       if (blockSpectators && frametime) {
-               // WORKAROUND: only use dropclient in server frames (frametime set).
-               // Never use it in cl_movement frames (frametime zero).
-               checkSpectatorBlock(this);
-    }
-
-       zoomstate_set = false;
-
-       // Check for nameless players
-       if (isInvisibleString(this.netname)) {
-               this.netname = strzone(sprintf("Player#%d", this.playerid));
-               // stuffcmd(this, strcat("name ", this.netname, "\n")); // maybe?
-       }
-       if (this.netname != this.netname_previous) {
-               if (autocvar_sv_eventlog) {
-                       GameLogEcho(strcat(":name:", ftos(this.playerid), ":", this.netname));
-        }
-               if (this.netname_previous) strunzone(this.netname_previous);
-               this.netname_previous = strzone(this.netname);
-       }
-
-       // version nagging
-       if (this.version_nagtime && this.cvar_g_xonoticversion && time > this.version_nagtime) {
-        this.version_nagtime = 0;
-        if (strstrofs(this.cvar_g_xonoticversion, "git", 0) >= 0 || strstrofs(this.cvar_g_xonoticversion, "autobuild", 0) >= 0) {
-            // git client
-        } else if (strstrofs(autocvar_g_xonoticversion, "git", 0) >= 0 || strstrofs(autocvar_g_xonoticversion, "autobuild", 0) >= 0) {
-            // git server
-            Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_BETA, autocvar_g_xonoticversion, this.cvar_g_xonoticversion);
-        } else {
-            int r = vercmp(this.cvar_g_xonoticversion, autocvar_g_xonoticversion);
-            if (r < 0) { // old client
-                Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_OUTDATED, autocvar_g_xonoticversion, this.cvar_g_xonoticversion);
-            } else if (r > 0) { // old server
-                Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_OLD, autocvar_g_xonoticversion, this.cvar_g_xonoticversion);
-            }
-        }
-    }
-
-       // GOD MODE info
-       if (!(this.flags & FL_GODMODE) && this.max_armorvalue)
-       {
-               Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_GODMODE_OFF, this.max_armorvalue);
-               this.max_armorvalue = 0;
-       }
-
-       if (STAT(FROZEN, this) == 2)
-       {
-               this.revive_progress = bound(0, this.revive_progress + frametime * this.revive_speed, 1);
-               this.health = max(1, this.revive_progress * start_health);
-               this.iceblock.alpha = bound(0.2, 1 - this.revive_progress, 1);
-
-               if (this.revive_progress >= 1)
-                       Unfreeze(this);
-       }
-       else if (STAT(FROZEN, this) == 3)
-       {
-               this.revive_progress = bound(0, this.revive_progress - frametime * this.revive_speed, 1);
-               this.health = max(0, autocvar_g_nades_ice_health + (start_health-autocvar_g_nades_ice_health) * this.revive_progress );
-
-               if (this.health < 1)
-               {
-                       if (this.vehicle)
-                               vehicles_exit(this.vehicle, VHEF_RELEASE);
-                       if(this.event_damage)
-                               this.event_damage(this, this, this.frozen_by, 1, DEATH_NADE_ICE_FREEZE.m_id, this.origin, '0 0 0');
-               }
-               else if (this.revive_progress <= 0)
-                       Unfreeze(this);
-       }
-
-       MUTATOR_CALLHOOK(PlayerPreThink, this);
-
-       if(autocvar_g_vehicles_enter && (time > this.last_vehiclecheck) && !gameover && !this.vehicle)
-       if(IS_PLAYER(this) && !STAT(FROZEN, this) && !IS_DEAD(this))
-       {
-               FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_vehicles_enter_radius, IS_VEHICLE(it),
-               {
-                       if(!IS_DEAD(it) && it.takedamage != DAMAGE_NO)
-                       if((it.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(it.owner, this))
-                       {
-                               Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_GUNNER);
-                       }
-                       else if(!it.owner)
-                       {
-                               if(!it.team || SAME_TEAM(this, it))
-                                       Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER);
-                               else if(autocvar_g_vehicles_steal)
-                                       Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_STEAL);
-                       }
-               });
-
-               this.last_vehiclecheck = time + 1;
-       }
-
-       if(!this.cvar_cl_newusekeysupported) // FIXME remove this - it was a stupid idea to begin with, we can JUST use the button
-       {
-               if(PHYS_INPUT_BUTTON_USE(this) && !this.usekeypressed)
-                       PlayerUseKey(this);
-               this.usekeypressed = PHYS_INPUT_BUTTON_USE(this);
-       }
-
-       if (IS_REAL_CLIENT(this))
-               PrintWelcomeMessage(this);
-
-       if (IS_PLAYER(this)) {
-               CheckRules_Player(this);
-
-               if (intermission_running) {
-                       IntermissionThink(this);
-                       return;
-               }
-
-               if (timeout_status == TIMEOUT_ACTIVE) {
-            // don't allow the player to turn around while game is paused
-                       // FIXME turn this into CSQC stuff
-                       this.v_angle = this.lastV_angle;
-                       this.angles = this.lastV_angle;
-                       this.fixangle = true;
-               }
-
-               if (frametime) player_powerups(this);
-
-               if (IS_DEAD(this)) {
-                       if (this.personal && g_race_qualifying) {
-                               if (time > this.respawn_time) {
-                                       STAT(RESPAWN_TIME, this) = this.respawn_time = time + 1; // only retry once a second
-                                       respawn(this);
-                                       this.impulse = CHIMPULSE_SPEEDRUN.impulse;
-                               }
-                       } else {
-                               if (frametime) player_anim(this);
-                               bool button_pressed = (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));
-
-                               switch(this.deadflag)
-                               {
-                                       case DEAD_DYING:
-                                       {
-                                               if ((this.respawn_flags & RESPAWN_FORCE) && !(this.respawn_time < this.respawn_time_max))
-                                                       this.deadflag = DEAD_RESPAWNING;
-                                               else if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE))
-                                                       this.deadflag = DEAD_DEAD;
-                                               break;
-                                       }
-                                       case DEAD_DEAD:
-                                       {
-                                               if (button_pressed)
-                                                       this.deadflag = DEAD_RESPAWNABLE;
-                                               else if (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE))
-                                                       this.deadflag = DEAD_RESPAWNING;
-                                               break;
-                                       }
-                                       case DEAD_RESPAWNABLE:
-                                       {
-                                               if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE))
-                                                       this.deadflag = DEAD_RESPAWNING;
-                                               break;
-                                       }
-                                       case DEAD_RESPAWNING:
-                                       {
-                                               if (time > this.respawn_time)
-                                               {
-                                                       this.respawn_time = time + 1; // only retry once a second
-                                                       this.respawn_time_max = this.respawn_time;
-                                                       respawn(this);
-                                               }
-                                               break;
-                                       }
-                               }
-
-                               ShowRespawnCountdown(this);
-
-                               if (this.respawn_flags & RESPAWN_SILENT)
-                                       STAT(RESPAWN_TIME, this) = 0;
-                               else if ((this.respawn_flags & RESPAWN_FORCE) && this.respawn_time < this.respawn_time_max)
-                               {
-                                       if (time < this.respawn_time)
-                                               STAT(RESPAWN_TIME, this) = this.respawn_time;
-                                       else if (this.deadflag != DEAD_RESPAWNING)
-                                               STAT(RESPAWN_TIME, this) = -this.respawn_time_max;
-                               }
-                               else
-                                       STAT(RESPAWN_TIME, this) = this.respawn_time;
-                       }
-
-                       // if respawning, invert stat_respawn_time to indicate this, the client translates it
-                       if (this.deadflag == DEAD_RESPAWNING && STAT(RESPAWN_TIME, this) > 0)
-                               STAT(RESPAWN_TIME, this) *= -1;
-
-                       return;
-               }
-
-               this.prevorigin = this.origin;
-
-               bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
-               if (this.hook.state) {
-                       do_crouch = false;
-               } else if (this.waterlevel >= WATERLEVEL_SWIMMING) {
-                       do_crouch = false;
-               } else if (this.vehicle) {
-                       do_crouch = false;
-               } else if (STAT(FROZEN, this)) {
-                       do_crouch = false;
-        }
-
-               if (do_crouch) {
-                       if (!this.crouch) {
-                               this.crouch = true;
-                               this.view_ofs = STAT(PL_CROUCH_VIEW_OFS, this);
-                               setsize(this, STAT(PL_CROUCH_MIN, this), STAT(PL_CROUCH_MAX, this));
-                               // setanim(this, this.anim_duck, false, true, true); // this anim is BROKEN anyway
-                       }
-               } else if (this.crouch) {
-            tracebox(this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this), this.origin, false, this);
-            if (!trace_startsolid) {
-                this.crouch = false;
-                this.view_ofs = STAT(PL_VIEW_OFS, this);
-                setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this));
-            }
-               }
-
-               FixPlayermodel(this);
-
-               // LordHavoc: allow firing on move frames (sub-ticrate), this gives better timing on slow servers
-               //if(frametime)
-               {
-                       this.items &= ~this.items_added;
-
-                       //for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-                       //{
-                               //.entity weaponentity = weaponentities[slot];
-                               //W_WeaponFrame(this, weaponentity);
-                       //}
-                       .entity weaponentity = weaponentities[0]; // TODO
-                       W_WeaponFrame(this, weaponentity);
-
-                       this.items_added = 0;
-                       if (this.items & ITEM_Jetpack.m_itemid && (this.items & ITEM_JetpackRegen.m_itemid || this.ammo_fuel >= 0.01))
-                this.items_added |= IT_FUEL;
-
-                       this.items |= this.items_added;
-               }
-
-               player_regen(this);
-
-               // WEAPONTODO: Add a weapon request for this
-               // rot vortex charge to the charge limit
-               if (WEP_CVAR(vortex, charge_rot_rate) && this.vortex_charge > WEP_CVAR(vortex, charge_limit) && this.vortex_charge_rottime < time)
-                       this.vortex_charge = bound(WEP_CVAR(vortex, charge_limit), this.vortex_charge - WEP_CVAR(vortex, charge_rot_rate) * frametime / W_TICSPERFRAME, 1);
-
-               if (frametime) player_anim(this);
-
-               // secret status
-               secrets_setstatus(this);
-
-               // monsters status
-               monsters_setstatus(this);
-
-               this.dmg_team = max(0, this.dmg_team - autocvar_g_teamdamage_resetspeed * frametime);
-       }
-       else if (gameover) {
-               if (intermission_running) IntermissionThink(this);
-               return;
-       }
-       else if (IS_OBSERVER(this)) {
-               ObserverThink(this);
-       }
-       else if (IS_SPEC(this)) {
-               SpectatorThink(this);
-       }
-
-       // WEAPONTODO: Add weapon request for this
-       if (!zoomstate_set) {
-               SetZoomState(this,
-                       PHYS_INPUT_BUTTON_ZOOM(this) || PHYS_INPUT_BUTTON_ZOOMSCRIPT(this)
-                       || (PHYS_INPUT_BUTTON_ATCK2(this) && PS(this).m_weapon == WEP_VORTEX)
-                       || (PHYS_INPUT_BUTTON_ATCK2(this) && PS(this).m_weapon == WEP_RIFLE && WEP_CVAR(rifle, secondary) == 0)
-               );
-    }
-
-       int oldspectatee_status = this.spectatee_status;
-       if (IS_SPEC(this)) {
-               this.spectatee_status = etof(this.enemy);
-       } else if (IS_OBSERVER(this)) {
-               this.spectatee_status = etof(this);
-       } else {
-               this.spectatee_status = 0;
-    }
-       if (this.spectatee_status != oldspectatee_status) {
-               ClientData_Touch(this);
-               if (g_race || g_cts) race_InitSpectator();
-       }
-
-       if (this.teamkill_soundtime && time > this.teamkill_soundtime)
-       {
-               this.teamkill_soundtime = 0;
-
-               entity e = this.teamkill_soundsource;
-               entity oldpusher = e.pusher;
-               e.pusher = this;
-               PlayerSound(e, playersound_teamshoot, CH_VOICE, VOL_BASEVOICE, VOICETYPE_LASTATTACKER_ONLY);
-               e.pusher = oldpusher;
-       }
-
-       if (this.taunt_soundtime && time > this.taunt_soundtime) {
-               this.taunt_soundtime = 0;
-               PlayerSound(this, playersound_taunt, CH_VOICE, VOL_BASEVOICE, VOICETYPE_AUTOTAUNT);
-       }
-
-       target_voicescript_next(this);
-
-       // WEAPONTODO: Move into weaponsystem somehow
-       // if a player goes unarmed after holding a loaded weapon, empty his clip size and remove the crosshair ammo ring
-       if (PS(this).m_weapon == WEP_Null)
-               this.clip_load = this.clip_size = 0;
-}
-
-void DrownPlayer(entity this)
-{
-       if(IS_DEAD(this))
-               return;
-
-       if (this.waterlevel != WATERLEVEL_SUBMERGED || this.vehicle)
-       {
-               if(this.air_finished < time)
-                       PlayerSound(this, playersound_gasp, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND);
-               this.air_finished = time + autocvar_g_balance_contents_drowndelay;
-               this.dmg = 2;
-       }
-       else if (this.air_finished < time)
-       {       // drown!
-               if (this.pain_finished < time)
-               {
-                       Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_drowning * autocvar_g_balance_contents_damagerate, DEATH_DROWN.m_id, this.origin, '0 0 0');
-                       this.pain_finished = time + 0.5;
-               }
-       }
-}
-
-void Player_Physics(entity this)
-{
-       set_movetype(this, ((this.move_qcphysics) ? MOVETYPE_NONE : this.move_movetype));
-
-       if(!this.move_qcphysics)
-               return;
-
-       int mt = this.move_movetype;
-
-       if(mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH || mt == MOVETYPE_PHYSICS)
-       {
-               this.move_qcphysics = false;
-               set_movetype(this, mt);
-               return;
-       }
-
-       if(!frametime && !this.pm_frametime)
-               return;
-
-       Movetype_Physics_NoMatchTicrate(this, this.pm_frametime, true);
-
-       this.pm_frametime = 0;
-}
-
-/*
-=============
-PlayerPostThink
-
-Called every frame for each client after the physics are run
-=============
-*/
-.float idlekick_lasttimeleft;
-void PlayerPostThink (entity this)
-{
-       Player_Physics(this);
-
-       if (sv_maxidle > 0)
-       if (frametime) // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
-       if (IS_REAL_CLIENT(this))
-       if (IS_PLAYER(this) || sv_maxidle_spectatorsareidle)
-       {
-               int totalClients = 0;
-               if(sv_maxidle_slots > 0)
-               {
-                       FOREACH_CLIENT(IS_REAL_CLIENT(it) || sv_maxidle_slots_countbots,
-                       {
-                               ++totalClients;
-                       });
-               }
-
-               if (sv_maxidle_slots > 0 && (maxclients - totalClients) > sv_maxidle_slots)
-               { /* do nothing */ }
-               else if (time - this.parm_idlesince < 1) // instead of (time == this.parm_idlesince) to support sv_maxidle <= 10
-               {
-                       if (this.idlekick_lasttimeleft)
-                       {
-                               this.idlekick_lasttimeleft = 0;
-                               Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_IDLING);
-                       }
-               }
-               else
-               {
-                       float timeleft = ceil(sv_maxidle - (time - this.parm_idlesince));
-                       if (timeleft == min(10, sv_maxidle - 1)) { // - 1 to support sv_maxidle <= 10
-                               if (!this.idlekick_lasttimeleft)
-                                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_DISCONNECT_IDLING, timeleft);
-                       }
-                       if (timeleft <= 0) {
-                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_KICK_IDLING, this.netname);
-                               dropclient(this);
-                               return;
-                       }
-                       else if (timeleft <= 10) {
-                               if (timeleft != this.idlekick_lasttimeleft) {
-                                   Send_Notification(NOTIF_ONE, this, MSG_ANNCE, Announcer_PickNumber(CNT_IDLE, timeleft));
-                }
-                               this.idlekick_lasttimeleft = timeleft;
-                       }
-               }
-       }
-
-       CheatFrame(this);
-
-       //CheckPlayerJump();
-
-       if (IS_PLAYER(this)) {
-               DrownPlayer(this);
-               CheckRules_Player(this);
-               UpdateChatBubble(this);
-               if (this.impulse) ImpulseCommands(this);
-               if (intermission_running) return; // intermission or finale
-               GetPressedKeys(this);
-       }
-
-       if (this.waypointsprite_attachedforcarrier) {
-           vector v = healtharmor_maxdamage(this.health, this.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id);
-               WaypointSprite_UpdateHealth(this.waypointsprite_attachedforcarrier, '1 0 0' * v);
-    }
-
-       playerdemo_write(this);
-
-       CSQCMODEL_AUTOUPDATE(this);
-}
diff --git a/qcsrc/server/cl_client.qh b/qcsrc/server/cl_client.qh
deleted file mode 100644 (file)
index 35ff6e9..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-#pragma once
-
-void ClientState_attach(entity this);
-
-CLASS(Client, Object)
-    /** Client name */
-    ATTRIB(Client, netname, string, this.netname);
-    ATTRIB(Client, colormap, int, this.colormap);
-    ATTRIB(Client, team, int, this.team);
-    ATTRIB(Client, clientcolors, int, this.clientcolors);
-    /** Client IP */
-    ATTRIB(Client, netaddress, string, this.netaddress);
-    ATTRIB(Client, playermodel, string, this.playermodel);
-    ATTRIB(Client, playerskin, int, this.playerskin);
-
-    /** fingerprint of CA key the player used to authenticate */
-    ATTRIB(Client, crypto_keyfp, string, this.crypto_keyfp);
-    /** fingerprint of CA key the server used to authenticate to the player */
-    ATTRIB(Client, crypto_mykeyfp, string, this.crypto_mykeyfp);
-    /** fingerprint of ID used by the player entity, or string_null if not identified */
-    ATTRIB(Client, crypto_idfp, string, this.crypto_idfp);
-    /** set if the player's ID has been signed */
-    ATTRIB(Client, crypto_idfp_signed, bool, this.crypto_idfp_signed);
-    /** the string "AES128" if encrypting, and string_null if plaintext */
-    ATTRIB(Client, crypto_encryptmethod, string, this.crypto_encryptmethod);
-    /** the string "HMAC-SHA256" if signing, and string_null if plaintext */
-    ATTRIB(Client, crypto_signmethod, string, this.crypto_signmethod);
-
-    // custom
-
-    ATTRIB(Client, playerid, int, this.playerid);
-
-    METHOD(Client, m_unwind, bool(Client this));
-
-    STATIC_METHOD(Client, Add, void(Client this, int _team));
-    STATIC_METHOD(Client, Remove, void(Client this));
-
-    INIT(Client) {
-        if (this.m_unwind(this)) return this;
-        make_impure(this);
-        this.classname = "player_joining";
-        static int playerid_last;
-        this.playerid = ++playerid_last;
-        ClientState_attach(this);
-    }
-    DESTRUCTOR(Client) {
-        Client_Remove(this);
-    }
-    CONSTRUCTOR(Client, string name) {
-        CONSTRUCT(Client);
-        this.netname = name;
-        this.netaddress = "local";
-        this.playermodel = "models/player/megaerebus.iqm";
-    }
-ENDCLASS(Client)
-
-CLASS(Observer, Client)
-    INIT(Observer) {
-        this.classname = STR_OBSERVER;
-    }
-    DESTRUCTOR(Observer) { }
-ENDCLASS(Observer)
-
-CLASS(Spectator, Client)
-    INIT(Spectator) {
-        this.classname = STR_SPECTATOR;
-    }
-    DESTRUCTOR(Spectator) { }
-ENDCLASS(Spectator)
-
-CLASS(Player, Client)
-    INIT(Player) {
-        this.classname = STR_PLAYER;
-    }
-    DESTRUCTOR(Player) { }
-ENDCLASS(Player)
-
-METHOD(Client, m_unwind, bool(Client this))
-{
-    TC(Client, this);
-    #define UNWIND(class) MACRO_BEGIN if (this.instanceOf##class) { METHOD_REFERENCE(class, dtorimpl)(this); } MACRO_END
-    switch (this.classname) {
-        case "Observer":
-            UNWIND(Spectator);
-            UNWIND(Player);
-            return true;
-        case "Spectator":
-            UNWIND(Observer);
-            UNWIND(Player);
-            return true;
-        case "Player":
-            UNWIND(Observer);
-            UNWIND(Spectator);
-            return true;
-    }
-    #undef UNWIND
-    return false;
-}
-
-float c1, c2, c3, c4;
-
-void play_countdown(entity this, float finished, Sound samp);
-
-float CalcRotRegen(float current, float regenstable, float regenfactor, float regenlinear, float regenframetime, float rotstable, float rotfactor, float rotlinear, float rotframetime, float limit);
-
-bool Spectate(entity this, entity pl);
-
-#define SPECTATE_COPY() [[accumulate]] void SpectateCopy(entity this, entity spectatee)
-#define SPECTATE_COPYFIELD(fld) SPECTATE_COPY() { this.(fld) = spectatee.(fld); }
diff --git a/qcsrc/server/cl_impulse.qc b/qcsrc/server/cl_impulse.qc
deleted file mode 100644 (file)
index 00c4ec2..0000000
+++ /dev/null
@@ -1,606 +0,0 @@
-#include "cl_impulse.qh"
-#include "round_handler.qh"
-
-#include "bot/api.qh"
-
-#include "weapons/throwing.qh"
-#include "command/common.qh"
-#include "cheats.qh"
-#include "weapons/selection.qh"
-#include "weapons/tracing.qh"
-#include "weapons/weaponsystem.qh"
-
-#include <common/state.qh>
-
-#include "../common/minigames/sv_minigames.qh"
-
-#include "../common/weapons/all.qh"
-#include "../common/vehicles/sv_vehicles.qh"
-
-#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
-
-.entity vehicle;
-
-#define IMPULSE(id) _IMPULSE(IMP_##id)
-#define _IMPULSE(id) \
-       void id##_handle(entity this); \
-       STATIC_INIT_LATE(id) \
-       { \
-               id.impulse_handle = id##_handle; \
-       } \
-       void id##_handle(entity this)
-
-/**
- * Impulse map:
- *
- * 0 reserved (no input)
- *
- * 99: loaded
- *
- * 140: moving clone
- * 141: ctf speedrun
- * 142: fixed clone
- * 143: emergency teleport
- * 148: unfairly eliminate
- *
- * TODO:
- * 200 to 209: prev weapon shortcuts
- * 210 to 219: best weapon shortcuts
- * 220 to 229: next weapon shortcuts
- * 230 to 253: individual weapons (up to 24)
- */
-
-// weapon switching impulses
-
-#define X(slot) \
-       IMPULSE(weapon_group_##slot) \
-       { \
-               if (IS_DEAD(this)) \
-               { \
-                       this.impulse = IMP_weapon_group_##slot.impulse; \
-                       return; \
-               } \
-               W_NextWeaponOnImpulse(this, slot); \
-       }
-X(1)
-X(2)
-X(3)
-X(4)
-X(5)
-X(6)
-X(7)
-X(8)
-X(9)
-X(0)
-#undef X
-
-// custom order weapon cycling
-
-#define X(slot, dir) \
-       IMPULSE(weapon_priority_##slot##_##dir) \
-       { \
-               if (this.vehicle) return; \
-               if (IS_DEAD(this)) \
-               { \
-                       this.impulse = IMP_weapon_priority_##slot##_##dir.impulse; \
-                       return; \
-               } \
-               noref int prev = -1; \
-               noref int best =  0; \
-               noref int next = +1; \
-               W_CycleWeapon(this, this.cvar_cl_weaponpriorities[slot], dir); \
-       }
-X(0, prev)
-X(1, prev)
-X(2, prev)
-X(3, prev)
-X(4, prev)
-X(5, prev)
-X(6, prev)
-X(7, prev)
-X(8, prev)
-X(9, prev)
-
-X(0, best)
-X(1, best)
-X(2, best)
-X(3, best)
-X(4, best)
-X(5, best)
-X(6, best)
-X(7, best)
-X(8, best)
-X(9, best)
-
-X(0, next)
-X(1, next)
-X(2, next)
-X(3, next)
-X(4, next)
-X(5, next)
-X(6, next)
-X(7, next)
-X(8, next)
-X(9, next)
-#undef X
-
-// direct weapons
-
-#define X(i) \
-       IMPULSE(weapon_byid_##i) \
-       { \
-               if (this.vehicle) return; \
-               if (IS_DEAD(this)) \
-               { \
-                       this.impulse = IMP_weapon_byid_##i.impulse; \
-                       return; \
-               } \
-               W_SwitchWeapon(this, Weapons_from(WEP_FIRST + i)); \
-       }
-X(0)
-X(1)
-X(2)
-X(3)
-X(4)
-X(5)
-X(6)
-X(7)
-X(8)
-X(9)
-X(10)
-X(11)
-X(12)
-X(13)
-X(14)
-X(15)
-X(16)
-X(17)
-X(18)
-X(19)
-X(20)
-X(21)
-X(22)
-X(23)
-#undef X
-
-IMPULSE(weapon_next_byid)
-{
-       if (this.vehicle) return;
-       if (IS_DEAD(this))
-       {
-               this.impulse = IMP_weapon_next_byid.impulse;
-               return;
-       }
-       W_NextWeapon(this, 0);
-}
-
-IMPULSE(weapon_prev_byid)
-{
-       if (this.vehicle) return;
-       if (IS_DEAD(this))
-       {
-               this.impulse = IMP_weapon_prev_byid.impulse;
-               return;
-       }
-       W_PreviousWeapon(this, 0);
-}
-
-IMPULSE(weapon_next_bygroup)
-{
-       if (this.vehicle) return;
-       if (IS_DEAD(this))
-       {
-               this.impulse = IMP_weapon_next_bygroup.impulse;
-               return;
-       }
-       W_NextWeapon(this, 1);
-}
-
-IMPULSE(weapon_prev_bygroup)
-{
-       if (this.vehicle) return;
-       if (IS_DEAD(this))
-       {
-               this.impulse = IMP_weapon_prev_bygroup.impulse;
-               return;
-       }
-       W_PreviousWeapon(this, 1);
-}
-
-IMPULSE(weapon_next_bypriority)
-{
-       if (this.vehicle) return;
-       if (IS_DEAD(this))
-       {
-               this.impulse = IMP_weapon_next_bypriority.impulse;
-               return;
-       }
-       W_NextWeapon(this, 2);
-}
-
-IMPULSE(weapon_prev_bypriority)
-{
-       if (this.vehicle) return;
-       if (IS_DEAD(this))
-       {
-               this.impulse = IMP_weapon_prev_bypriority.impulse;
-               return;
-       }
-       W_PreviousWeapon(this, 2);
-}
-
-IMPULSE(weapon_last)
-{
-       if (this.vehicle) return;
-       if (IS_DEAD(this)) return;
-       W_LastWeapon(this);
-}
-
-IMPULSE(weapon_best)
-{
-       if (this.vehicle) return;
-       if (IS_DEAD(this)) return;
-       W_SwitchWeapon(this, w_getbestweapon(this));
-}
-
-IMPULSE(weapon_drop)
-{
-       if (this.vehicle) return;
-       if (IS_DEAD(this)) return;
-       W_ThrowWeapon(this, weaponentities[0], W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), '0 0 0', true);
-}
-
-IMPULSE(weapon_reload)
-{
-       if (this.vehicle) return;
-       if (IS_DEAD(this)) return;
-       if (forbidWeaponUse(this)) return;
-       Weapon w = PS(this).m_weapon;
-       entity actor = this;
-       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-       {
-               .entity weaponentity = weaponentities[slot];
-               w.wr_reload(w, actor, weaponentity);
-       }
-}
-
-void ImpulseCommands(entity this)
-{
-       if (gameover) return;
-
-       int imp = this.impulse;
-       if (!imp) return;
-       this.impulse = 0;
-
-       if (MinigameImpulse(this, imp)) return;
-
-       if (timeout_status == TIMEOUT_ACTIVE) return;  // don't allow any impulses while the game is paused
-
-       // allow only weapon change impulses when not in round time
-       if (round_handler_IsActive() && !round_handler_IsRoundStarted())
-       {
-               #define X(id) case IMP_##id.impulse:
-               switch (imp)
-               {
-                       X(weapon_group_0)
-                       X(weapon_group_1)
-                       X(weapon_group_2)
-                       X(weapon_group_3)
-                       X(weapon_group_4)
-                       X(weapon_group_5)
-                       X(weapon_group_6)
-                       X(weapon_group_7)
-                       X(weapon_group_8)
-                       X(weapon_group_9)
-                       X(weapon_next_byid)
-                       X(weapon_prev_byid)
-                       X(weapon_next_bygroup)
-                       X(weapon_prev_bygroup)
-                       X(weapon_next_bypriority)
-                       X(weapon_prev_bypriority)
-                       X(weapon_last)
-                       X(weapon_best)
-                       X(weapon_reload)
-                       X(weapon_priority_0_prev)
-            X(weapon_priority_1_prev)
-            X(weapon_priority_2_prev)
-            X(weapon_priority_3_prev)
-            X(weapon_priority_4_prev)
-            X(weapon_priority_5_prev)
-            X(weapon_priority_6_prev)
-            X(weapon_priority_7_prev)
-            X(weapon_priority_8_prev)
-            X(weapon_priority_9_prev)
-            X(weapon_priority_0_next)
-                       X(weapon_priority_1_next)
-                       X(weapon_priority_2_next)
-                       X(weapon_priority_3_next)
-                       X(weapon_priority_4_next)
-                       X(weapon_priority_5_next)
-                       X(weapon_priority_6_next)
-                       X(weapon_priority_7_next)
-                       X(weapon_priority_8_next)
-                       X(weapon_priority_9_next)
-                       X(weapon_priority_0_best)
-            X(weapon_priority_1_best)
-            X(weapon_priority_2_best)
-            X(weapon_priority_3_best)
-            X(weapon_priority_4_best)
-            X(weapon_priority_5_best)
-            X(weapon_priority_6_best)
-            X(weapon_priority_7_best)
-            X(weapon_priority_8_best)
-            X(weapon_priority_9_best)
-            X(weapon_byid_0)
-            X(weapon_byid_1)
-            X(weapon_byid_2)
-            X(weapon_byid_3)
-            X(weapon_byid_4)
-            X(weapon_byid_5)
-            X(weapon_byid_6)
-            X(weapon_byid_7)
-            X(weapon_byid_8)
-            X(weapon_byid_9)
-            X(weapon_byid_10)
-            X(weapon_byid_11)
-            X(weapon_byid_12)
-            X(weapon_byid_13)
-            X(weapon_byid_14)
-            X(weapon_byid_15)
-            X(weapon_byid_16)
-            X(weapon_byid_17)
-            X(weapon_byid_18)
-            X(weapon_byid_19)
-            X(weapon_byid_20)
-            X(weapon_byid_21)
-            X(weapon_byid_22)
-            X(weapon_byid_23)
-                       break;
-                       default: return;
-               }
-#undef X
-       }
-
-       if (vehicle_impulse(this, imp)) return;
-
-       if (CheatImpulse(this, imp)) return;
-
-       FOREACH(IMPULSES, it.impulse == imp, {
-               void(entity) f = it.impulse_handle;
-               if (!f) continue;
-               f(this);
-               return;
-       });
-}
-
-IMPULSE(use)
-{
-       PlayerUseKey(this);
-}
-
-IMPULSE(waypoint_personal_here)
-{
-       entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.origin, RADARICON_WAYPOINT);
-       if (wp) WaypointSprite_Ping(wp);
-       sprint(this, "personal waypoint spawned at location\n");
-}
-
-IMPULSE(waypoint_personal_crosshair)
-{
-       WarpZone_crosshair_trace(this);
-       entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, trace_endpos, RADARICON_WAYPOINT);
-       if (wp) WaypointSprite_Ping(wp);
-       sprint(this, "personal waypoint spawned at crosshair\n");
-}
-
-IMPULSE(waypoint_personal_death)
-{
-       if (!this.death_origin) return;
-       entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.death_origin, RADARICON_WAYPOINT);
-       if (wp) WaypointSprite_Ping(wp);
-       sprint(this, "personal waypoint spawned at death location\n");
-}
-
-IMPULSE(waypoint_here_follow)
-{
-       if (!teamplay) return;
-       if (IS_DEAD(this)) return;
-       if (!MUTATOR_CALLHOOK(HelpMePing, this))
-       {
-               entity wp = WaypointSprite_Attach(WP_Helpme, this, true, RADARICON_HELPME);
-               if (!wp) WaypointSprite_HelpMePing(this.waypointsprite_attachedforcarrier);
-               else WaypointSprite_Ping(wp);
-       }
-       sprint(this, "HELP ME attached\n");
-}
-
-IMPULSE(waypoint_here_here)
-{
-       entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.origin, RADARICON_HERE);
-       if (wp) WaypointSprite_Ping(wp);
-       sprint(this, "HERE spawned at location\n");
-}
-
-IMPULSE(waypoint_here_crosshair)
-{
-       WarpZone_crosshair_trace(this);
-       entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, trace_endpos, RADARICON_HERE);
-       if (wp) WaypointSprite_Ping(wp);
-       sprint(this, "HERE spawned at crosshair\n");
-}
-
-IMPULSE(waypoint_here_death)
-{
-       if (!this.death_origin) return;
-       entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.death_origin, RADARICON_HERE);
-       if (wp) WaypointSprite_Ping(wp);
-       sprint(this, "HERE spawned at death location\n");
-}
-
-IMPULSE(waypoint_danger_here)
-{
-       entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.origin, RADARICON_DANGER);
-       if (wp) WaypointSprite_Ping(wp);
-       sprint(this, "DANGER spawned at location\n");
-}
-
-IMPULSE(waypoint_danger_crosshair)
-{
-       WarpZone_crosshair_trace(this);
-       entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, trace_endpos, RADARICON_DANGER);
-       if (wp) WaypointSprite_Ping(wp);
-       sprint(this, "DANGER spawned at crosshair\n");
-}
-
-IMPULSE(waypoint_danger_death)
-{
-       if (!this.death_origin) return;
-       entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.death_origin, RADARICON_DANGER);
-       if (wp) WaypointSprite_Ping(wp);
-       sprint(this, "DANGER spawned at death location\n");
-}
-
-IMPULSE(waypoint_clear_personal)
-{
-       WaypointSprite_ClearPersonal(this);
-       if (this.personal)
-       {
-               delete(this.personal);
-               this.personal = NULL;
-       }
-       sprint(this, "personal waypoint cleared\n");
-}
-
-IMPULSE(waypoint_clear)
-{
-       WaypointSprite_ClearOwned(this);
-       if (this.personal)
-       {
-               delete(this.personal);
-               this.personal = NULL;
-       }
-       sprint(this, "all waypoints cleared\n");
-}
-
-IMPULSE(navwaypoint_spawn)
-{
-       if (!autocvar_g_waypointeditor) return;
-       waypoint_schedulerelink(waypoint_spawn(this.origin, this.origin, 0));
-       bprint(strcat("Waypoint spawned at ", vtos(this.origin), "\n"));
-}
-
-IMPULSE(navwaypoint_remove)
-{
-       if (!autocvar_g_waypointeditor) return;
-       entity e = navigation_findnearestwaypoint(this, false);
-       if (!e) return;
-       if (e.wpflags & WAYPOINTFLAG_GENERATED) return;
-       bprint(strcat("Waypoint removed at ", vtos(e.origin), "\n"));
-       waypoint_remove(e);
-}
-
-IMPULSE(navwaypoint_relink)
-{
-       if (!autocvar_g_waypointeditor) return;
-       waypoint_schedulerelinkall();
-}
-
-IMPULSE(navwaypoint_save)
-{
-       if (!autocvar_g_waypointeditor) return;
-       waypoint_saveall();
-}
-
-IMPULSE(navwaypoint_unreachable)
-{
-       if (!autocvar_g_waypointeditor) return;
-       IL_EACH(g_waypoints, true,
-       {
-               it.colormod = '0.5 0.5 0.5';
-               it.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
-       });
-       entity e2 = navigation_findnearestwaypoint(this, false);
-       navigation_markroutes(this, e2);
-
-       int j, m;
-
-       j = 0;
-       m = 0;
-       IL_EACH(g_waypoints, it.wpcost >= 10000000,
-       {
-               LOG_INFO("unreachable: ", etos(it), " ", vtos(it.origin), "\n");
-               it.colormod_z = 8;
-               it.effects |= EF_NODEPTHTEST | EF_BLUE;
-               ++j;
-               ++m;
-       });
-       if (j) LOG_INFOF("%d waypoints cannot be reached from here in any way (marked with blue light)\n", j);
-       navigation_markroutes_inverted(e2);
-
-       j = 0;
-       IL_EACH(g_waypoints, it.wpcost >= 10000000,
-       {
-               LOG_INFO("cannot reach me: ", etos(it), " ", vtos(it.origin), "\n");
-               it.colormod_x = 8;
-               if (!(it.effects & EF_NODEPTHTEST))  // not already reported before
-                       ++m;
-               it.effects |= EF_NODEPTHTEST | EF_RED;
-               ++j;
-       });
-       if (j) LOG_INFOF("%d waypoints cannot walk to here in any way (marked with red light)\n", j);
-       if (m) LOG_INFOF("%d waypoints have been marked total\n", m);
-
-       j = 0;
-       FOREACH_ENTITY_CLASS("info_player_deathmatch", true,
-       {
-               vector org = it.origin;
-               tracebox(it.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - '0 0 512', MOVE_NOMONSTERS, NULL);
-               setorigin(it, trace_endpos);
-               if (navigation_findnearestwaypoint(it, false))
-               {
-                       setorigin(it, org);
-                       it.effects &= ~EF_NODEPTHTEST;
-                       it.model = "";
-               }
-               else
-               {
-                       setorigin(it, org);
-                       LOG_INFO("spawn without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
-                       it.effects |= EF_NODEPTHTEST;
-                       _setmodel(it, this.model);
-                       it.frame = this.frame;
-                       it.skin = this.skin;
-                       it.colormod = '8 0.5 8';
-                       setsize(it, '0 0 0', '0 0 0');
-                       ++j;
-               }
-       });
-       if (j) LOG_INFOF("%d spawnpoints have no nearest waypoint (marked by player model)\n", j);
-
-       j = 0;
-       FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
-       {
-               it.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
-               it.colormod = '0.5 0.5 0.5';
-       });
-       FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
-       {
-               if (navigation_findnearestwaypoint(it, false)) continue;
-               LOG_INFO("item without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
-               it.effects |= EF_NODEPTHTEST | EF_RED;
-               it.colormod_x = 8;
-               ++j;
-       });
-       if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked away from (marked with red light)\n", j);
-
-       j = 0;
-       FOREACH_ENTITY_FLAGS(flags, FL_ITEM,
-       {
-               if (navigation_findnearestwaypoint(it, true)) continue;
-               LOG_INFO("item without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
-               it.effects |= EF_NODEPTHTEST | EF_BLUE;
-               it.colormod_z = 8;
-               ++j;
-       });
-       if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked to (marked with blue light)\n", j);
-}
diff --git a/qcsrc/server/cl_impulse.qh b/qcsrc/server/cl_impulse.qh
deleted file mode 100644 (file)
index 50edc2c..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-void ImpulseCommands(entity this);
diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc
deleted file mode 100644 (file)
index 1ae97c9..0000000
+++ /dev/null
@@ -1,962 +0,0 @@
-#include "cl_player.qh"
-
-#include "bot/api.qh"
-#include "cheats.qh"
-#include "g_damage.qh"
-#include "g_subs.qh"
-#include "miscfunctions.qh"
-#include "portals.qh"
-#include "teamplay.qh"
-#include "weapons/throwing.qh"
-#include "command/common.qh"
-#include "../common/state.qh"
-#include "../common/anim.qh"
-#include "../common/animdecide.qh"
-#include "../common/csqcmodel_settings.qh"
-#include "../common/deathtypes/all.qh"
-#include "../common/triggers/subs.qh"
-#include "../common/playerstats.qh"
-#include "../lib/csqcmodel/sv_model.qh"
-
-#include "../common/minigames/sv_minigames.qh"
-
-#include "../common/physics/player.qh"
-#include "../common/effects/qc/all.qh"
-#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
-#include "../common/triggers/include.qh"
-
-#include "weapons/weaponstats.qh"
-
-#include "../common/animdecide.qh"
-
-void Drop_Special_Items(entity player)
-{
-       // called when the player has become stuck or frozen
-       // so objective items aren't stuck with the player
-
-       MUTATOR_CALLHOOK(DropSpecialItems, player);
-}
-
-void CopyBody_Think(entity this)
-{
-       if(this.CopyBody_nextthink && time > this.CopyBody_nextthink)
-       {
-               this.CopyBody_think(this);
-               if(wasfreed(this))
-                       return;
-               this.CopyBody_nextthink = this.nextthink;
-               this.CopyBody_think = getthink(this);
-               setthink(this, CopyBody_Think);
-       }
-       CSQCMODEL_AUTOUPDATE(this);
-       this.nextthink = time;
-}
-void CopyBody(entity this, float keepvelocity)
-{
-       if (this.effects & EF_NODRAW)
-               return;
-       entity clone = new(body);
-       clone.enemy = this;
-       clone.lip = this.lip;
-       clone.colormap = this.colormap;
-       clone.iscreature = this.iscreature;
-       clone.teleportable = this.teleportable;
-       clone.damagedbycontents = this.damagedbycontents;
-       clone.angles = this.angles;
-       clone.v_angle = this.v_angle;
-       clone.avelocity = this.avelocity;
-       clone.damageforcescale = this.damageforcescale;
-       clone.effects = this.effects;
-       clone.glowmod = this.glowmod;
-       clone.event_damage = this.event_damage;
-       clone.anim_state = this.anim_state;
-       clone.anim_time = this.anim_time;
-       clone.anim_lower_action = this.anim_lower_action;
-       clone.anim_lower_time = this.anim_lower_time;
-       clone.anim_upper_action = this.anim_upper_action;
-       clone.anim_upper_time = this.anim_upper_time;
-       clone.anim_implicit_state = this.anim_implicit_state;
-       clone.anim_implicit_time = this.anim_implicit_time;
-       clone.anim_lower_implicit_action = this.anim_lower_implicit_action;
-       clone.anim_lower_implicit_time = this.anim_lower_implicit_time;
-       clone.anim_upper_implicit_action = this.anim_upper_implicit_action;
-       clone.anim_upper_implicit_time = this.anim_upper_implicit_time;
-       clone.dphitcontentsmask = this.dphitcontentsmask;
-       clone.death_time = this.death_time;
-       clone.pain_finished = this.pain_finished;
-       clone.health = this.health;
-       clone.armorvalue = this.armorvalue;
-       clone.armortype = this.armortype;
-       clone.model = this.model;
-       clone.modelindex = this.modelindex;
-       clone.skin = this.skin;
-       clone.species = this.species;
-       clone.move_qcphysics = false; // don't run gamecode logic on clones, too many
-       set_movetype(clone, this.move_movetype);
-       clone.solid = this.solid;
-       clone.ballistics_density = this.ballistics_density;
-       clone.takedamage = this.takedamage;
-       setcefc(clone, getcefc(this));
-       clone.uncustomizeentityforclient = this.uncustomizeentityforclient;
-       clone.uncustomizeentityforclient_set = this.uncustomizeentityforclient_set;
-       if (keepvelocity == 1)
-               clone.velocity = this.velocity;
-       clone.oldvelocity = clone.velocity;
-       clone.alpha = this.alpha;
-       clone.fade_time = this.fade_time;
-       clone.fade_rate = this.fade_rate;
-       //clone.weapon = this.weapon;
-       setorigin(clone, this.origin);
-       setsize(clone, this.mins, this.maxs);
-       clone.prevorigin = this.origin;
-       clone.reset = SUB_Remove;
-       clone._ps = this._ps;
-
-       Drag_MoveDrag(this, clone);
-
-       if(clone.colormap <= maxclients && clone.colormap > 0)
-               clone.colormap = 1024 + this.clientcolors;
-
-       CSQCMODEL_AUTOINIT(clone);
-       clone.CopyBody_nextthink = this.nextthink;
-       clone.CopyBody_think = getthink(this);
-       clone.nextthink = time;
-       setthink(clone, CopyBody_Think);
-       // "bake" the current animation frame for clones (they don't get clientside animation)
-       animdecide_load_if_needed(clone);
-       animdecide_setframes(clone, false, frame, frame1time, frame2, frame2time);
-}
-
-void player_setupanimsformodel(entity this)
-{
-       // load animation info
-       animdecide_load_if_needed(this);
-       animdecide_setstate(this, 0, false);
-}
-
-void player_anim(entity this)
-{
-       int deadbits = (this.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2));
-       if(IS_DEAD(this)) {
-               if (!deadbits) {
-                       // Decide on which death animation to use.
-                       if(random() < 0.5)
-                               deadbits = ANIMSTATE_DEAD1;
-                       else
-                               deadbits = ANIMSTATE_DEAD2;
-               }
-       } else {
-               // Clear a previous death animation.
-               deadbits = 0;
-       }
-       int animbits = deadbits;
-       if(STAT(FROZEN, this))
-               animbits |= ANIMSTATE_FROZEN;
-       if(this.move_movetype == MOVETYPE_FOLLOW)
-               animbits |= ANIMSTATE_FOLLOW;
-       if(this.crouch)
-               animbits |= ANIMSTATE_DUCK;
-       animdecide_setstate(this, animbits, false);
-       animdecide_setimplicitstate(this, IS_ONGROUND(this));
-}
-
-void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{
-       float take, save;
-       vector v;
-       Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, this, attacker);
-
-       // damage resistance (ignore most of the damage from a bullet or similar)
-       damage = max(damage - 5, 1);
-
-       v = healtharmor_applydamage(this.armorvalue, autocvar_g_balance_armor_blockpercent, deathtype, damage);
-       take = v.x;
-       save = v.y;
-
-       if(sound_allowed(MSG_BROADCAST, attacker))
-       {
-               if (save > 10)
-                       sound (this, CH_SHOTS, SND_ARMORIMPACT, VOL_BASE, ATTEN_NORM);
-               else if (take > 30)
-                       sound (this, CH_SHOTS, SND_BODYIMPACT2, VOL_BASE, ATTEN_NORM);
-               else if (take > 10)
-                       sound (this, CH_SHOTS, SND_BODYIMPACT1, VOL_BASE, ATTEN_NORM);
-       }
-
-       if (take > 50)
-               Violence_GibSplash_At(hitloc, force * -0.1, 3, 1, this, attacker);
-       if (take > 100)
-               Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, this, attacker);
-
-       this.armorvalue = this.armorvalue - save;
-       this.health = this.health - take;
-       // pause regeneration for 5 seconds
-       this.pauseregen_finished = max(this.pauseregen_finished, time + autocvar_g_balance_pause_health_regen);
-
-       this.dmg_save = this.dmg_save + save;//max(save - 10, 0);
-       this.dmg_take = this.dmg_take + take;//max(take - 10, 0);
-       this.dmg_inflictor = inflictor;
-
-       if (this.health <= -autocvar_sv_gibhealth && this.alpha >= 0)
-       {
-               // don't use any animations as a gib
-               this.frame = 0;
-               // view just above the floor
-               this.view_ofs = '0 0 4';
-
-               Violence_GibSplash(this, 1, 1, attacker);
-               this.alpha = -1;
-               this.solid = SOLID_NOT; // restore later
-               this.takedamage = DAMAGE_NO; // restore later
-               this.damagedbycontents = false;
-       }
-}
-
-void calculate_player_respawn_time(entity this)
-{
-       if(g_ca)
-               return;
-
-       float gametype_setting_tmp;
-       float sdelay_max = GAMETYPE_DEFAULTED_SETTING(respawn_delay_max);
-       float sdelay_small = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small);
-       float sdelay_large = GAMETYPE_DEFAULTED_SETTING(respawn_delay_large);
-       float sdelay_small_count = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small_count);
-       float sdelay_large_count = GAMETYPE_DEFAULTED_SETTING(respawn_delay_large_count);
-       float waves = GAMETYPE_DEFAULTED_SETTING(respawn_waves);
-
-       float pcount = 1;  // Include myself whether or not team is already set right and I'm a "player".
-       if (teamplay)
-       {
-               FOREACH_CLIENT(IS_PLAYER(it) && it != this, LAMBDA(
-                       if(it.team == this.team)
-                               ++pcount;
-               ));
-               if (sdelay_small_count == 0)
-                       sdelay_small_count = 1;
-               if (sdelay_large_count == 0)
-                       sdelay_large_count = 1;
-       }
-       else
-       {
-               FOREACH_CLIENT(IS_PLAYER(it) && it != this, LAMBDA(
-                       ++pcount;
-               ));
-               if (sdelay_small_count == 0)
-               {
-                       if (g_cts)
-                       {
-                               // Players play independently. No point in requiring enemies.
-                               sdelay_small_count = 1;
-                       }
-                       else
-                       {
-                               // Players play AGAINST each other. Enemies required.
-                               sdelay_small_count = 2;
-                       }
-               }
-               if (sdelay_large_count == 0)
-               {
-                       if (g_cts)
-                       {
-                               // Players play independently. No point in requiring enemies.
-                               sdelay_large_count = 1;
-                       }
-                       else
-                       {
-                               // Players play AGAINST each other. Enemies required.
-                               sdelay_large_count = 2;
-                       }
-               }
-       }
-
-       float sdelay;
-
-       if (pcount <= sdelay_small_count)
-               sdelay = sdelay_small;
-       else if (pcount >= sdelay_large_count)
-               sdelay = sdelay_large;
-       else  // NOTE: this case implies sdelay_large_count > sdelay_small_count.
-               sdelay = sdelay_small + (sdelay_large - sdelay_small) * (pcount - sdelay_small_count) / (sdelay_large_count - sdelay_small_count);
-
-       if(waves)
-               this.respawn_time = ceil((time + sdelay) / waves) * waves;
-       else
-               this.respawn_time = time + sdelay;
-
-       if(sdelay < sdelay_max)
-               this.respawn_time_max = time + sdelay_max;
-       else
-               this.respawn_time_max = this.respawn_time;
-
-       if((sdelay + waves >= 5.0) && (this.respawn_time - time > 1.75))
-               this.respawn_countdown = 10; // first number to count down from is 10
-       else
-               this.respawn_countdown = -1; // do not count down
-
-       if(autocvar_g_forced_respawn)
-               this.respawn_flags = this.respawn_flags | RESPAWN_FORCE;
-}
-
-void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{
-       float take, save, dh, da;
-       vector v;
-       float valid_damage_for_weaponstats;
-       float excess;
-
-       dh = max(this.health, 0);
-       da = max(this.armorvalue, 0);
-
-       if(!DEATH_ISSPECIAL(deathtype))
-       {
-               damage *= sqrt(bound(1.0, this.cvar_cl_handicap, 100.0));
-               if(this != attacker)
-                       damage /= sqrt(bound(1.0, attacker.cvar_cl_handicap, 100.0));
-       }
-
-       if(DEATH_ISWEAPON(deathtype, WEP_TUBA))
-       {
-               // tuba causes blood to come out of the ears
-               vector ear1, ear2;
-               vector d;
-               float f;
-               ear1 = this.origin;
-               ear1_z += 0.125 * this.view_ofs.z + 0.875 * this.maxs.z; // 7/8
-               ear2 = ear1;
-               makevectors(this.angles);
-               ear1 += v_right * -10;
-               ear2 += v_right * +10;
-               d = inflictor.origin - this.origin;
-               if (d)
-                       f = (d * v_right) / vlen(d); // this is cos of angle of d and v_right!
-               else
-                       f = 0;  // Assum ecenter.
-               force = v_right * vlen(force);
-               Violence_GibSplash_At(ear1, force * -1, 2, bound(0, damage, 25) / 2 * (0.5 - 0.5 * f), this, attacker);
-               Violence_GibSplash_At(ear2, force,      2, bound(0, damage, 25) / 2 * (0.5 + 0.5 * f), this, attacker);
-               if(f > 0)
-               {
-                       hitloc = ear1;
-                       force = force * -1;
-               }
-               else
-               {
-                       hitloc = ear2;
-                       // force is already good
-               }
-       }
-       else
-               Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, this, attacker);
-
-
-       v = healtharmor_applydamage(this.armorvalue, autocvar_g_balance_armor_blockpercent, deathtype, damage);
-       take = v.x;
-       save = v.y;
-
-       if(attacker == this)
-       {
-               // don't reset pushltime for this damage as it may be an attempt to
-               // escape a lava pit or similar
-               //this.pushltime = 0;
-               this.istypefrag = 0;
-       }
-       else if(IS_PLAYER(attacker))
-       {
-               this.pusher = attacker;
-               this.pushltime = time + autocvar_g_maxpushtime;
-               this.istypefrag = PHYS_INPUT_BUTTON_CHAT(this);
-       }
-       else if(time < this.pushltime)
-       {
-               attacker = this.pusher;
-               this.pushltime = max(this.pushltime, time + 0.6);
-       }
-       else
-       {
-               this.pushltime = 0;
-               this.istypefrag = 0;
-       }
-
-       if (time < this.spawnshieldtime && autocvar_g_spawnshield_blockdamage < 1)
-       {
-               vector v = healtharmor_applydamage(this.armorvalue, max(0, autocvar_g_spawnshield_blockdamage), deathtype, damage);
-               take = v.x;
-               save = v.y;
-       }
-
-       MUTATOR_CALLHOOK(PlayerDamage_SplitHealthArmor, inflictor, attacker, this, force, take, save, deathtype, damage);
-       take = bound(0, M_ARGV(4, float), this.health);
-       save = bound(0, M_ARGV(5, float), this.armorvalue);
-       excess = max(0, damage - take - save);
-
-       if(sound_allowed(MSG_BROADCAST, attacker))
-       {
-               if (save > 10)
-                       sound (this, CH_SHOTS, SND_ARMORIMPACT, VOL_BASE, ATTEN_NORM);
-               else if (take > 30)
-                       sound (this, CH_SHOTS, SND_BODYIMPACT2, VOL_BASE, ATTEN_NORM);
-               else if (take > 10)
-                       sound (this, CH_SHOTS, SND_BODYIMPACT1, VOL_BASE, ATTEN_NORM); // FIXME possibly remove them?
-       }
-
-       if (take > 50)
-               Violence_GibSplash_At(hitloc, force * -0.1, 3, 1, this, attacker);
-       if (take > 100)
-               Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, this, attacker);
-
-       if (time >= this.spawnshieldtime || autocvar_g_spawnshield_blockdamage < 1)
-       {
-               if (!(this.flags & FL_GODMODE))
-               {
-                       this.armorvalue = this.armorvalue - save;
-                       this.health = this.health - take;
-                       // pause regeneration for 5 seconds
-                       if(take)
-                               this.pauseregen_finished = max(this.pauseregen_finished, time + autocvar_g_balance_pause_health_regen);
-
-                       if (time > this.pain_finished)          //Don't switch pain sequences like crazy
-                       {
-                               this.pain_finished = time + 0.5;        //Supajoe
-
-                               if(autocvar_sv_gentle < 1) {
-                                       if(this.classname != "body") // pain anim is BORKED on our ZYMs, FIXME remove this once we have good models
-                                       {
-                                               if (!this.animstate_override)
-                                               {
-                                                       if (random() > 0.5)
-                                                               animdecide_setaction(this, ANIMACTION_PAIN1, true);
-                                                       else
-                                                               animdecide_setaction(this, ANIMACTION_PAIN2, true);
-                                               }
-                                       }
-
-                                       if(sound_allowed(MSG_BROADCAST, attacker))
-                                       if((this.health < 2 * WEP_CVAR_PRI(blaster, damage) * autocvar_g_balance_selfdamagepercent + 1) || !(DEATH_WEAPONOF(deathtype).spawnflags & WEP_FLAG_CANCLIMB) || attacker != this) // WEAPONTODO: create separate limit for pain notification with laser
-                                       if(this.health > 1)
-                                       // exclude pain sounds for laserjumps as long as you aren't REALLY low on health and would die of the next two
-                                       {
-                                               if(deathtype == DEATH_FALL.m_id)
-                                                       PlayerSound(this, playersound_fall, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
-                                               else if(this.health > 75)
-                                                       PlayerSound(this, playersound_pain100, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
-                                               else if(this.health > 50)
-                                                       PlayerSound(this, playersound_pain75, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
-                                               else if(this.health > 25)
-                                                       PlayerSound(this, playersound_pain50, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
-                                               else
-                                                       PlayerSound(this, playersound_pain25, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
-                                       }
-                               }
-                       }
-
-                       // throw off bot aim temporarily
-                       float shake;
-                       if(IS_BOT_CLIENT(this) && this.health >= 1)
-                       {
-                               shake = damage * 5 / (bound(0,skill,100) + 1);
-                               this.v_angle_x = this.v_angle.x + (random() * 2 - 1) * shake;
-                               this.v_angle_y = this.v_angle.y + (random() * 2 - 1) * shake;
-                               this.v_angle_x = bound(-90, this.v_angle.x, 90);
-                       }
-               }
-               else
-                       this.max_armorvalue += (save + take);
-       }
-       this.dmg_save = this.dmg_save + save;//max(save - 10, 0);
-       this.dmg_take = this.dmg_take + take;//max(take - 10, 0);
-       this.dmg_inflictor = inflictor;
-
-       if (this != attacker) {
-               float realdmg = damage - excess;
-               if (IS_PLAYER(attacker)) {
-                       PlayerScore_Add(attacker, SP_DMG, realdmg);
-               }
-               if (IS_PLAYER(this)) {
-                       PlayerScore_Add(this, SP_DMGTAKEN, realdmg);
-               }
-       }
-
-       bool abot = (IS_BOT_CLIENT(attacker));
-       bool vbot = (IS_BOT_CLIENT(this));
-
-       valid_damage_for_weaponstats = 0;
-       Weapon awep = WEP_Null;
-
-       if(vbot || IS_REAL_CLIENT(this))
-       if(abot || IS_REAL_CLIENT(attacker))
-       if(attacker && this != attacker)
-       if(DIFF_TEAM(this, attacker))
-       {
-               if(DEATH_ISSPECIAL(deathtype))
-                       awep = PS(attacker).m_weapon;
-               else
-                       awep = DEATH_WEAPONOF(deathtype);
-               valid_damage_for_weaponstats = 1;
-       }
-
-       dh = dh - max(this.health, 0);
-       da = da - max(this.armorvalue, 0);
-       if(valid_damage_for_weaponstats)
-       {
-               WeaponStats_LogDamage(awep.m_id, abot, PS(this).m_weapon.m_id, vbot, dh + da);
-       }
-       if (dh + da)
-       {
-               MUTATOR_CALLHOOK(PlayerDamaged, attacker, this, dh, da, hitloc, deathtype);
-       }
-
-       if (this.health < 1)
-       {
-               float defer_ClientKill_Now_TeamChange;
-               defer_ClientKill_Now_TeamChange = false;
-
-               if(this.alivetime)
-               {
-                       PS_GR_P_ADDVAL(this, PLAYERSTATS_ALIVETIME, time - this.alivetime);
-                       this.alivetime = 0;
-               }
-
-               if(valid_damage_for_weaponstats)
-                       WeaponStats_LogKill(awep.m_id, abot, PS(this).m_weapon.m_id, vbot);
-
-               if(autocvar_sv_gentle < 1)
-               if(sound_allowed(MSG_BROADCAST, attacker))
-               {
-                       if(deathtype == DEATH_DROWN.m_id)
-                               PlayerSound(this, playersound_drown, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
-                       else
-                               PlayerSound(this, playersound_death, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
-               }
-
-               // get rid of kill indicator
-               if(this.killindicator)
-               {
-                       delete(this.killindicator);
-                       this.killindicator = NULL;
-                       if(this.killindicator_teamchange)
-                               defer_ClientKill_Now_TeamChange = true;
-
-                       if(this.classname == "body")
-                       if(deathtype == DEATH_KILL.m_id)
-                       {
-                               // for the lemmings fans, a small harmless explosion
-                               Send_Effect(EFFECT_ROCKET_EXPLODE, this.origin, '0 0 0', 1);
-                       }
-               }
-
-               // print an obituary message
-               if(this.classname != "body")
-                       Obituary (attacker, inflictor, this, deathtype);
-
-        // increment frag counter for used weapon type
-        Weapon w = DEATH_WEAPONOF(deathtype);
-        if(w != WEP_Null)
-       if(accuracy_isgooddamage(attacker, this))
-        attacker.accuracy.(accuracy_frags[w.m_id-1]) += 1;
-
-               MUTATOR_CALLHOOK(PlayerDies, inflictor, attacker, this, deathtype, damage);
-               excess = M_ARGV(4, float);
-
-               Weapon wep = PS(this).m_weapon;
-               /*for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-               {
-                       .entity weaponentity = weaponentities[slot];
-                       wep.wr_playerdeath(wep, this, weaponentity);
-               }*/
-               .entity weaponentity = weaponentities[0]; // TODO: unhardcode
-               wep.wr_playerdeath(wep, this, weaponentity);
-
-               RemoveGrapplingHook(this);
-
-               Portal_ClearAllLater(this);
-
-               this.fixangle = true;
-
-               if(defer_ClientKill_Now_TeamChange)
-                       ClientKill_Now_TeamChange(this); // can turn player into spectator
-
-               // player could have been miraculously resuscitated ;)
-               // e.g. players in freezetag get frozen, they don't really die
-               if(this.health >= 1 || !(IS_PLAYER(this) || this.classname == "body"))
-                       return;
-
-               // when we get here, player actually dies
-
-               Unfreeze(this); // remove any icy remains
-               this.health = 0; // Unfreeze resets health, so we need to set it back
-
-               // clear waypoints
-               WaypointSprite_PlayerDead(this);
-               // throw a weapon
-               SpawnThrownWeapon(this, this.origin + (this.mins + this.maxs) * 0.5, PS(this).m_switchweapon.m_id);
-
-               // become fully visible
-               this.alpha = default_player_alpha;
-               // make the corpse upright (not tilted)
-               this.angles_x = 0;
-               this.angles_z = 0;
-               // don't spin
-               this.avelocity = '0 0 0';
-               // view from the floor
-               this.view_ofs = '0 0 -8';
-               // toss the corpse
-               set_movetype(this, MOVETYPE_TOSS);
-               // shootable corpse
-               this.solid = SOLID_CORPSE;
-               this.ballistics_density = autocvar_g_ballistics_density_corpse;
-               // don't stick to the floor
-               UNSET_ONGROUND(this);
-               // dying animation
-               this.deadflag = DEAD_DYING;
-
-               // when to allow respawn
-               calculate_player_respawn_time(this);
-
-               this.death_time = time;
-               if (random() < 0.5)
-                       animdecide_setstate(this, this.anim_state | ANIMSTATE_DEAD1, true);
-               else
-                       animdecide_setstate(this, this.anim_state | ANIMSTATE_DEAD2, true);
-               if (this.maxs.z > 5)
-               {
-                       this.maxs_z = 5;
-                       setsize(this, this.mins, this.maxs);
-               }
-               // set damage function to corpse damage
-               this.event_damage = PlayerCorpseDamage;
-               // call the corpse damage function just in case it wants to gib
-               this.event_damage(this, inflictor, attacker, excess, deathtype, hitloc, force);
-
-               // set up to fade out later
-               SUB_SetFade (this, time + 6 + random (), 1);
-               // reset body think wrapper broken by SUB_SetFade
-               if(this.classname == "body" && getthink(this) != CopyBody_Think) {
-                       this.CopyBody_think = getthink(this);
-                       this.CopyBody_nextthink = this.nextthink;
-                       setthink(this, CopyBody_Think);
-                       this.nextthink = time;
-               }
-
-               if(autocvar_sv_gentle > 0 || autocvar_ekg || this.classname == "body") {
-                       // remove corpse
-                       // clones don't run any animation code any more, so we must gib them when they die :(
-                       PlayerCorpseDamage(this, inflictor, attacker, autocvar_sv_gibhealth+1.0, deathtype, hitloc, force);
-               }
-
-               // reset fields the weapons may use just in case
-               FOREACH(Weapons, it != WEP_Null, LAMBDA(
-                       it.wr_resetplayer(it, this);
-                       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-                       {
-                               ATTACK_FINISHED_FOR(this, it.m_id, slot) = 0;
-                       }
-               ));
-       }
-}
-
-void MoveToTeam(entity client, int team_colour, int type)
-{
-       int lockteams_backup = lockteams;  // backup any team lock
-       lockteams = 0;  // disable locked teams
-       TeamchangeFrags(client);  // move the players frags
-       SetPlayerColors(client, team_colour - 1);  // set the players colour
-       Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE.m_id, client.origin, '0 0 0');  // kill the player
-       lockteams = lockteams_backup;  // restore the team lock
-       LogTeamchange(client.playerid, client.team, type);
-}
-
-/** print(), but only print if the server is not local */
-void dedicated_print(string input)
-{
-       if (server_is_dedicated) print(input);
-}
-
-/**
- * message "": do not say, just test flood control
- * return value:
- *   1 = accept
- *   0 = reject
- *  -1 = fake accept
- */
-int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodcontrol)
-{
-       if (!teamsay && !privatesay) if (substring(msgin, 0, 1) == " ")
-        msgin = substring(msgin, 1, -1); // work around DP say bug (say_team does not have this!)
-
-       msgin = formatmessage(source, msgin);
-
-    string colorstr;
-       if (!IS_PLAYER(source))
-               colorstr = "^0"; // black for spectators
-       else if(teamplay)
-               colorstr = Team_ColorCode(source.team);
-       else
-       {
-               colorstr = "";
-               teamsay = false;
-       }
-
-       if(intermission_running)
-               teamsay = false;
-
-    if (!source) {
-               colorstr = "";
-               teamsay = false;
-    }
-
-       if(msgin != "")
-               msgin = trigger_magicear_processmessage_forallears(source, teamsay, privatesay, msgin);
-
-       /*
-        * using bprint solves this... me stupid
-       // how can we prevent the message from appearing in a listen server?
-       // for now, just give "say" back and only handle say_team
-       if(!teamsay)
-       {
-               clientcommand(source, strcat("say ", msgin));
-               return;
-       }
-       */
-
-    string namestr = "";
-    if (source)
-        namestr = autocvar_g_chat_teamcolors ? playername(source) : source.netname;
-
-    string colorprefix = (strdecolorize(namestr) == namestr) ? "^3" : "^7";
-
-    string msgstr, cmsgstr;
-    string privatemsgprefix = string_null;
-    int privatemsgprefixlen = 0;
-       if (msgin == "") {
-        msgstr = cmsgstr = "";
-       } else {
-               if(privatesay)
-               {
-                       msgstr = strcat("\{1}\{13}* ", colorprefix, namestr, "^3 tells you: ^7");
-                       privatemsgprefixlen = strlen(msgstr);
-                       msgstr = strcat(msgstr, msgin);
-                       cmsgstr = strcat(colorstr, colorprefix, namestr, "^3 tells you:\n^7", msgin);
-                       if(autocvar_g_chat_teamcolors)
-                               privatemsgprefix = strcat("\{1}\{13}* ^3You tell ", playername(privatesay), ": ^7");
-                       else
-                               privatemsgprefix = strcat("\{1}\{13}* ^3You tell ", privatesay.netname, ": ^7");
-               }
-               else if(teamsay)
-               {
-                       if(strstrofs(msgin, "/me", 0) >= 0)
-                       {
-                               //msgin = strreplace("/me", "", msgin);
-                               //msgin = substring(msgin, 3, strlen(msgin));
-                               msgin = strreplace("/me", strcat(colorstr, "(", colorprefix, namestr, colorstr, ")^7"), msgin);
-                               msgstr = strcat("\{1}\{13}^4* ", "^7", msgin);
-                       }
-                       else
-                               msgstr = strcat("\{1}\{13}", colorstr, "(", colorprefix, namestr, colorstr, ") ^7", msgin);
-                       cmsgstr = strcat(colorstr, "(", colorprefix, namestr, colorstr, ")\n^7", msgin);
-               }
-               else
-               {
-                       if(strstrofs(msgin, "/me", 0) >= 0)
-                       {
-                               //msgin = strreplace("/me", "", msgin);
-                               //msgin = substring(msgin, 3, strlen(msgin));
-                               msgin = strreplace("/me", strcat(colorprefix, namestr), msgin);
-                               msgstr = strcat("\{1}^4* ", "^7", msgin);
-                       }
-                       else {
-                msgstr = "\{1}";
-                msgstr = strcat(msgstr, (namestr != "") ? strcat(colorprefix, namestr, "^7: ") : "^7");
-                msgstr = strcat(msgstr, msgin);
-            }
-                       cmsgstr = "";
-               }
-               msgstr = strcat(strreplace("\n", " ", msgstr), "\n"); // newlines only are good for centerprint
-       }
-
-       string fullmsgstr = msgstr;
-       string fullcmsgstr = cmsgstr;
-
-       // FLOOD CONTROL
-       int flood = 0;
-       var .float flood_field = floodcontrol_chat;
-       if(floodcontrol)
-       {
-               float flood_spl;
-               float flood_burst;
-               float flood_lmax;
-               float lines;
-               if(privatesay)
-               {
-                       flood_spl = autocvar_g_chat_flood_spl_tell;
-                       flood_burst = autocvar_g_chat_flood_burst_tell;
-                       flood_lmax = autocvar_g_chat_flood_lmax_tell;
-                       flood_field = floodcontrol_chattell;
-               }
-               else if(teamsay)
-               {
-                       flood_spl = autocvar_g_chat_flood_spl_team;
-                       flood_burst = autocvar_g_chat_flood_burst_team;
-                       flood_lmax = autocvar_g_chat_flood_lmax_team;
-                       flood_field = floodcontrol_chatteam;
-               }
-               else
-               {
-                       flood_spl = autocvar_g_chat_flood_spl;
-                       flood_burst = autocvar_g_chat_flood_burst;
-                       flood_lmax = autocvar_g_chat_flood_lmax;
-                       flood_field = floodcontrol_chat;
-               }
-               flood_burst = max(0, flood_burst - 1);
-               // to match explanation in default.cfg, a value of 3 must allow three-line bursts and not four!
-
-               // do flood control for the default line size
-               if(msgstr != "")
-               {
-                       getWrappedLine_remaining = msgstr;
-                       msgstr = "";
-                       lines = 0;
-                       while(getWrappedLine_remaining && (!flood_lmax || lines <= flood_lmax))
-                       {
-                               msgstr = strcat(msgstr, " ", getWrappedLineLen(82.4289758859709, strlennocol)); // perl averagewidth.pl < gfx/vera-sans.width
-                               ++lines;
-                       }
-                       msgstr = substring(msgstr, 1, strlen(msgstr) - 1);
-
-                       if(getWrappedLine_remaining != "")
-                       {
-                               msgstr = strcat(msgstr, "\n");
-                               flood = 2;
-                       }
-
-                       if (time >= source.(flood_field))
-                       {
-                               source.(flood_field) = max(time - flood_burst * flood_spl, source.(flood_field)) + lines * flood_spl;
-                       }
-                       else
-                       {
-                               flood = 1;
-                               msgstr = fullmsgstr;
-                       }
-               }
-               else
-               {
-                       if (time >= source.(flood_field))
-                               source.(flood_field) = max(time - flood_burst * flood_spl, source.(flood_field)) + flood_spl;
-                       else
-                               flood = 1;
-               }
-
-               if (timeout_status == TIMEOUT_ACTIVE) // when game is paused, no flood protection
-                       source.(flood_field) = flood = 0;
-       }
-
-    string sourcemsgstr, sourcecmsgstr;
-       if(flood == 2) // cannot happen for empty msgstr
-       {
-               if(autocvar_g_chat_flood_notify_flooder)
-               {
-                       sourcemsgstr = strcat(msgstr, "\n^3FLOOD CONTROL: ^7message too long, trimmed\n");
-                       sourcecmsgstr = "";
-               }
-               else
-               {
-                       sourcemsgstr = fullmsgstr;
-                       sourcecmsgstr = fullcmsgstr;
-               }
-               cmsgstr = "";
-       }
-       else
-       {
-               sourcemsgstr = msgstr;
-               sourcecmsgstr = cmsgstr;
-       }
-
-       if (!privatesay && source && !IS_PLAYER(source))
-       {
-               if (!intermission_running)
-                       if(teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !(warmup_stage || gameover)))
-                               teamsay = -1; // spectators
-       }
-
-       if(flood)
-               LOG_INFO("NOTE: ", playername(source), "^7 is flooding.\n");
-
-       // build sourcemsgstr by cutting off a prefix and replacing it by the other one
-       if(privatesay)
-               sourcemsgstr = strcat(privatemsgprefix, substring(sourcemsgstr, privatemsgprefixlen, -1));
-
-    int ret;
-       if(source.muted)
-       {
-               // always fake the message
-               ret = -1;
-       }
-       else if(flood == 1)
-       {
-               if (autocvar_g_chat_flood_notify_flooder)
-               {
-                       sprint(source, strcat("^3FLOOD CONTROL: ^7wait ^1", ftos(source.(flood_field) - time), "^3 seconds\n"));
-                       ret = 0;
-               }
-               else
-                       ret = -1;
-       }
-       else
-       {
-               ret = 1;
-       }
-
-       if(sourcemsgstr != "" && ret != 0)
-       {
-               if(ret < 0) // faked message, because the player is muted
-               {
-                       sprint(source, sourcemsgstr);
-                       if(sourcecmsgstr != "" && !privatesay)
-                               centerprint(source, sourcecmsgstr);
-               }
-               else if(privatesay) // private message, between 2 people only
-               {
-                       sprint(source, sourcemsgstr);
-                       sprint(privatesay, msgstr);
-                       if (!autocvar_g_chat_tellprivacy) { dedicated_print(msgstr); } // send to server console too if "tellprivacy" is disabled
-                       if(cmsgstr != "")
-                               centerprint(privatesay, cmsgstr);
-               }
-               else if ( teamsay && source.active_minigame )
-               {
-                       sprint(source, sourcemsgstr);
-                       dedicated_print(msgstr); // send to server console too
-                       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && it.active_minigame == source.active_minigame, sprint(it, msgstr));
-               }
-               else if(teamsay > 0) // team message, only sent to team mates
-               {
-                       sprint(source, sourcemsgstr);
-                       dedicated_print(msgstr); // send to server console too
-                       if(sourcecmsgstr != "")
-                               centerprint(source, sourcecmsgstr);
-                       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source && it.team == source.team, {
-                               sprint(it, msgstr);
-                               if(cmsgstr != "")
-                                       centerprint(it, cmsgstr);
-                       });
-               }
-               else if(teamsay < 0) // spectator message, only sent to spectators
-               {
-                       sprint(source, sourcemsgstr);
-                       dedicated_print(msgstr); // send to server console too
-                       FOREACH_CLIENT(!IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source, sprint(it, msgstr));
-               }
-               else
-               {
-            if (source) {
-                sprint(source, sourcemsgstr);
-                dedicated_print(msgstr); // send to server console too
-                MX_Say(strcat(playername(source), "^7: ", msgin));
-            }
-            FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source, sprint(it, msgstr));
-        }
-       }
-
-       return ret;
-}
diff --git a/qcsrc/server/cl_player.qh b/qcsrc/server/cl_player.qh
deleted file mode 100644 (file)
index 3e2b860..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#pragma once
-
-.entity pusher;
-.float pushltime;
-.float istypefrag;
-
-.float CopyBody_nextthink;
-.void(entity this) CopyBody_think;
-void CopyBody_Think(entity this);
-void CopyBody(entity this, float keepvelocity);
-
-void dedicated_print(string input);
-
-void player_setupanimsformodel(entity this);
-
-void player_anim(entity this);
-
-void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
-
-// g_<gametype>_str:
-// If 0, default is used.
-// If <0, 0 is used.
-// Otherwise, g_str (default value) is used.
-// For consistency, negative values there are mapped to zero too.
-#define GAMETYPE_DEFAULTED_SETTING(str) \
-       ((gametype_setting_tmp = cvar(strcat("g_", GetGametype(), "_" #str))), \
-       (gametype_setting_tmp < 0) ? 0 \
-       : (gametype_setting_tmp == 0 || autocvar_g_respawn_delay_forced) ? max(0, autocvar_g_##str) \
-       : gametype_setting_tmp)
-
-void calculate_player_respawn_time(entity this);
-
-void ClientKill_Now_TeamChange(entity this);
-
-void MoveToTeam(entity client, float team_colour, float type);
-
-void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
-
-/** to be used by `prvm_edictset server playernumber muted 1` */
-.float muted;
-int Say(entity source, float teamsay, entity privatesay, string msgin, float floodcontrol);
diff --git a/qcsrc/server/client.qc b/qcsrc/server/client.qc
new file mode 100644 (file)
index 0000000..f71afe7
--- /dev/null
@@ -0,0 +1,2601 @@
+#include "client.qh"
+
+#include "anticheat.qh"
+#include "impulse.qh"
+#include "player.qh"
+#include "ipban.qh"
+#include "miscfunctions.qh"
+#include "portals.qh"
+#include "teamplay.qh"
+#include "playerdemo.qh"
+#include "spawnpoints.qh"
+#include "g_damage.qh"
+#include "g_hook.qh"
+#include "command/common.qh"
+#include "cheats.qh"
+#include "g_world.qh"
+#include "race.qh"
+#include "antilag.qh"
+#include "campaign.qh"
+#include "command/common.qh"
+#include "scores_rules.qh"
+
+#include "bot/api.qh"
+
+#include "../common/ent_cs.qh"
+#include <common/state.qh>
+
+#include <common/effects/qc/globalsound.qh>
+
+#include "../common/triggers/func/conveyor.qh"
+#include "../common/triggers/teleporters.qh"
+
+#include "../common/vehicles/all.qh"
+
+#include "weapons/hitplot.qh"
+#include "weapons/weaponsystem.qh"
+
+#include "../common/net_notice.qh"
+#include "../common/physics/player.qh"
+
+#include "../common/items/_mod.qh"
+
+#include "../common/mutators/mutator/waypoints/all.qh"
+
+#include "../common/triggers/subs.qh"
+#include "../common/triggers/triggers.qh"
+#include "../common/triggers/trigger/secret.qh"
+
+#include "../common/minigames/sv_minigames.qh"
+
+#include "../common/items/inventory.qh"
+
+#include "../common/monsters/sv_monsters.qh"
+
+#include "../lib/warpzone/server.qh"
+
+STATIC_METHOD(Client, Add, void(Client this, int _team))
+{
+    ClientConnect(this);
+    TRANSMUTE(Player, this);
+    this.frame = 12; // 7
+    this.team = _team;
+    PutClientInServer(this);
+}
+
+void PutObserverInServer(entity this);
+
+STATIC_METHOD(Client, Remove, void(Client this))
+{
+    TRANSMUTE(Observer, this);
+    PutClientInServer(this);
+    ClientDisconnect(this);
+}
+
+void send_CSQC_teamnagger() {
+       WriteHeader(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
+}
+
+int CountSpectators(entity player, entity to)
+{
+       if(!player) { return 0; } // not sure how, but best to be safe
+
+       int spec_count = 0;
+
+       FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
+       {
+               spec_count++;
+       });
+
+       return spec_count;
+}
+
+void WriteSpectators(entity player, entity to)
+{
+       if(!player) { return; } // not sure how, but best to be safe
+
+       FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
+       {
+               WriteByte(MSG_ENTITY, num_for_edict(it));
+       });
+}
+
+bool ClientData_Send(entity this, entity to, int sf)
+{
+       assert(to == this.owner, return false);
+
+       entity e = to;
+       if (IS_SPEC(e)) e = e.enemy;
+
+       sf = 0;
+       if (e.race_completed)       sf |= 1; // forced scoreboard
+       if (to.spectatee_status)    sf |= 2; // spectator ent number follows
+       if (e.zoomstate)            sf |= 4; // zoomed
+       if (e.porto_v_angle_held)   sf |= 8; // angles held
+       if (autocvar_sv_showspectators) sf |= 16; // show spectators
+
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA);
+       WriteByte(MSG_ENTITY, sf);
+
+       if (sf & 2)
+       {
+               WriteByte(MSG_ENTITY, to.spectatee_status);
+       }
+       if (sf & 8)
+       {
+               WriteAngle(MSG_ENTITY, e.v_angle.x);
+               WriteAngle(MSG_ENTITY, e.v_angle.y);
+       }
+
+       if(sf & 16)
+       {
+               float specs = CountSpectators(e, to);
+               WriteByte(MSG_ENTITY, specs);
+               WriteSpectators(e, to);
+       }
+
+       return true;
+}
+
+void ClientData_Attach(entity this)
+{
+       Net_LinkEntity(this.clientdata = new_pure(clientdata), false, 0, ClientData_Send);
+       this.clientdata.drawonlytoclient = this;
+       this.clientdata.owner = this;
+}
+
+void ClientData_Detach(entity this)
+{
+       delete(this.clientdata);
+       this.clientdata = NULL;
+}
+
+void ClientData_Touch(entity e)
+{
+       e.clientdata.SendFlags = 1;
+
+       // make it spectatable
+       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != e && IS_SPEC(it) && it.enemy == e, LAMBDA(it.clientdata.SendFlags = 1));
+}
+
+.string netname_previous;
+
+void SetSpectatee(entity this, entity spectatee);
+void SetSpectatee_status(entity this, int spectatee_num);
+
+
+/*
+=============
+CheckPlayerModel
+
+Checks if the argument string can be a valid playermodel.
+Returns a valid one in doubt.
+=============
+*/
+string FallbackPlayerModel;
+string CheckPlayerModel(string plyermodel) {
+       if(FallbackPlayerModel != cvar_defstring("_cl_playermodel"))
+       {
+               // note: we cannot summon Don Strunzone here, some player may
+               // still have the model string set. In case anyone manages how
+               // to change a cvar default, we'll have a small leak here.
+               FallbackPlayerModel = strzone(cvar_defstring("_cl_playermodel"));
+       }
+       // only in right path
+       if( substring(plyermodel,0,14) != "models/player/")
+               return FallbackPlayerModel;
+       // only good file extensions
+       if(substring(plyermodel,-4,4) != ".zym")
+       if(substring(plyermodel,-4,4) != ".dpm")
+       if(substring(plyermodel,-4,4) != ".iqm")
+       if(substring(plyermodel,-4,4) != ".md3")
+       if(substring(plyermodel,-4,4) != ".psk")
+               return FallbackPlayerModel;
+       // forbid the LOD models
+       if(substring(plyermodel, -9,5) == "_lod1")
+               return FallbackPlayerModel;
+       if(substring(plyermodel, -9,5) == "_lod2")
+               return FallbackPlayerModel;
+       if(plyermodel != strtolower(plyermodel))
+               return FallbackPlayerModel;
+       // also, restrict to server models
+       if(autocvar_sv_servermodelsonly)
+       {
+               if(!fexists(plyermodel))
+                       return FallbackPlayerModel;
+       }
+       return plyermodel;
+}
+
+void setplayermodel(entity e, string modelname)
+{
+       precache_model(modelname);
+       _setmodel(e, modelname);
+       player_setupanimsformodel(e);
+       if(!autocvar_g_debug_globalsounds)
+               UpdatePlayerSounds(e);
+}
+
+void FixPlayermodel(entity player);
+/** putting a client as observer in the server */
+void PutObserverInServer(entity this)
+{
+    bool mutator_returnvalue = MUTATOR_CALLHOOK(MakePlayerObserver, this);
+       PlayerState_detach(this);
+
+       if (IS_PLAYER(this) && this.health >= 1) {
+        // despawn effect
+               Send_Effect(EFFECT_SPAWN_NEUTRAL, this.origin, '0 0 0', 1);
+    }
+
+    {
+        entity spot = SelectSpawnPoint(this, true);
+        if (!spot) LOG_FATAL("No spawnpoints for observers?!?");
+        this.angles = spot.angles;
+        this.angles_z = 0;
+        this.fixangle = true;
+        // offset it so that the spectator spawns higher off the ground, looks better this way
+        setorigin(this, spot.origin + STAT(PL_VIEW_OFS, NULL));
+        this.prevorigin = this.origin;
+        if (IS_REAL_CLIENT(this))
+        {
+            msg_entity = this;
+            WriteByte(MSG_ONE, SVC_SETVIEW);
+            WriteEntity(MSG_ONE, this);
+        }
+        // give the spectator some space between walls for MOVETYPE_FLY_WORLDONLY
+        // so that your view doesn't go into the ceiling with MOVETYPE_FLY_WORLDONLY, previously "PL_VIEW_OFS"
+        if(!autocvar_g_debug_globalsounds)
+        {
+               // needed for player sounds
+               this.model = "";
+               FixPlayermodel(this);
+        }
+        setmodel(this, MDL_Null);
+        setsize(this, STAT(PL_CROUCH_MIN, NULL), STAT(PL_CROUCH_MAX, NULL));
+        this.view_ofs = '0 0 0';
+    }
+
+    RemoveGrapplingHook(this);
+       Portal_ClearAll(this);
+       Unfreeze(this);
+       SetSpectatee(this, NULL);
+
+       if (this.alivetime)
+       {
+               if (!warmup_stage)
+                       PS_GR_P_ADDVAL(this, PLAYERSTATS_ALIVETIME, time - this.alivetime);
+               this.alivetime = 0;
+       }
+
+       if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE);
+
+       WaypointSprite_PlayerDead(this);
+
+       if (mutator_returnvalue) {
+           // mutator prevents resetting teams+score
+       } else {
+               this.team = -1;  // move this as it is needed to log the player spectating in eventlog
+        this.frags = FRAGS_SPECTATOR;
+        PlayerScore_Clear(this);  // clear scores when needed
+    }
+
+       if (this.killcount != FRAGS_SPECTATOR)
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, this.netname);
+               if(!intermission_running)
+               if(autocvar_g_chat_nospectators == 1 || (!(warmup_stage || gameover) && autocvar_g_chat_nospectators == 2))
+                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CHAT_NOSPECTATORS);
+
+               if(this.just_joined == false) {
+                       LogTeamchange(this.playerid, -1, 4);
+               } else
+                       this.just_joined = false;
+       }
+
+       accuracy_resend(this);
+
+       this.spectatortime = time;
+       if(this.bot_attack)
+               IL_REMOVE(g_bot_targets, this);
+       this.bot_attack = false;
+    this.hud = HUD_NORMAL;
+       TRANSMUTE(Observer, this);
+       this.iscreature = false;
+       this.teleportable = TELEPORT_SIMPLE;
+       this.damagedbycontents = false;
+       this.health = FRAGS_SPECTATOR;
+       SetSpectatee_status(this, etof(this));
+       this.takedamage = DAMAGE_NO;
+       this.solid = SOLID_NOT;
+       set_movetype(this, MOVETYPE_FLY_WORLDONLY); // user preference is controlled by playerprethink
+       this.flags = FL_CLIENT | FL_NOTARGET;
+       this.armorvalue = 666;
+       this.effects = 0;
+       this.armorvalue = autocvar_g_balance_armor_start;
+       this.pauserotarmor_finished = 0;
+       this.pauserothealth_finished = 0;
+       this.pauseregen_finished = 0;
+       this.damageforcescale = 0;
+       this.death_time = 0;
+       this.respawn_flags = 0;
+       this.respawn_time = 0;
+       this.stat_respawn_time = 0;
+       this.alpha = 0;
+       this.scale = 0;
+       this.fade_time = 0;
+       this.pain_frame = 0;
+       this.pain_finished = 0;
+       this.strength_finished = 0;
+       this.invincible_finished = 0;
+       this.superweapons_finished = 0;
+       this.pushltime = 0;
+       this.istypefrag = 0;
+       setthink(this, func_null);
+       this.nextthink = 0;
+       this.hook_time = 0;
+       this.deadflag = DEAD_NO;
+       this.crouch = false;
+       this.revival_time = 0;
+
+       this.items = 0;
+       this.weapons = '0 0 0';
+       this.drawonlytoclient = this;
+
+       this.weaponname = "";
+       this.weaponmodel = "";
+       for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+       {
+               this.weaponentities[slot] = NULL;
+       }
+       this.exteriorweaponentity = NULL;
+       this.killcount = FRAGS_SPECTATOR;
+       this.velocity = '0 0 0';
+       this.avelocity = '0 0 0';
+       this.punchangle = '0 0 0';
+       this.punchvector = '0 0 0';
+       this.oldvelocity = this.velocity;
+       this.fire_endtime = -1;
+       this.event_damage = func_null;
+
+       STAT(ACTIVEWEAPON, this) = WEP_Null.m_id;
+       STAT(SWITCHINGWEAPON, this) = WEP_Null.m_id;
+       STAT(SWITCHWEAPON, this) = WEP_Null.m_id;
+}
+
+int player_getspecies(entity this)
+{
+       get_model_parameters(this.model, this.skin);
+       int s = get_model_parameters_species;
+       get_model_parameters(string_null, 0);
+       if (s < 0) return SPECIES_HUMAN;
+       return s;
+}
+
+.float model_randomizer;
+void FixPlayermodel(entity player)
+{
+       string defaultmodel = "";
+       int defaultskin = 0;
+       if(autocvar_sv_defaultcharacter)
+       {
+               if(teamplay)
+               {
+                       string s = Static_Team_ColorName_Lower(player.team);
+                       if (s != "neutral")
+                       {
+                               defaultmodel = cvar_string(strcat("sv_defaultplayermodel_", s));
+                               defaultskin = cvar(strcat("sv_defaultplayerskin_", s));
+                       }
+               }
+
+               if(defaultmodel == "")
+               {
+                       defaultmodel = autocvar_sv_defaultplayermodel;
+                       defaultskin = autocvar_sv_defaultplayerskin;
+               }
+
+               int n = tokenize_console(defaultmodel);
+               if(n > 0)
+               {
+                       defaultmodel = argv(floor(n * player.model_randomizer));
+                       // However, do NOT randomize if the player-selected model is in the list.
+                       for (int i = 0; i < n; ++i)
+                               if ((argv(i) == player.playermodel && defaultskin == stof(player.playerskin)) || argv(i) == strcat(player.playermodel, ":", player.playerskin))
+                                       defaultmodel = argv(i);
+               }
+
+               int i = strstrofs(defaultmodel, ":", 0);
+               if(i >= 0)
+               {
+                       defaultskin = stof(substring(defaultmodel, i+1, -1));
+                       defaultmodel = substring(defaultmodel, 0, i);
+               }
+       }
+       if(autocvar_sv_defaultcharacterskin && !defaultskin)
+       {
+               if(teamplay)
+               {
+                       string s = Static_Team_ColorName_Lower(player.team);
+                       if (s != "neutral")
+                               defaultskin = cvar(strcat("sv_defaultplayerskin_", s));
+               }
+
+               if(!defaultskin)
+                       defaultskin = autocvar_sv_defaultplayerskin;
+       }
+
+       MUTATOR_CALLHOOK(FixPlayermodel, defaultmodel, defaultskin, player);
+       defaultmodel = M_ARGV(0, string);
+       defaultskin = M_ARGV(1, int);
+
+       bool chmdl = false;
+       int oldskin;
+       if(defaultmodel != "")
+       {
+               if (defaultmodel != player.model)
+               {
+                       vector m1 = player.mins;
+                       vector m2 = player.maxs;
+                       setplayermodel (player, defaultmodel);
+                       setsize (player, m1, m2);
+                       chmdl = true;
+               }
+
+               oldskin = player.skin;
+               player.skin = defaultskin;
+       } else {
+               if (player.playermodel != player.model || player.playermodel == "")
+               {
+                       player.playermodel = CheckPlayerModel(player.playermodel); // this is never "", so no endless loop
+                       vector m1 = player.mins;
+                       vector m2 = player.maxs;
+                       setplayermodel (player, player.playermodel);
+                       setsize (player, m1, m2);
+                       chmdl = true;
+               }
+
+               if(!autocvar_sv_defaultcharacterskin)
+               {
+                       oldskin = player.skin;
+                       player.skin = stof(player.playerskin);
+               }
+               else
+               {
+                       oldskin = player.skin;
+                       player.skin = defaultskin;
+               }
+       }
+
+       if(chmdl || oldskin != player.skin) // model or skin has changed
+       {
+               player.species = player_getspecies(player); // update species
+               if(!autocvar_g_debug_globalsounds)
+                       UpdatePlayerSounds(player); // update skin sounds
+       }
+
+       if(!teamplay)
+               if(strlen(autocvar_sv_defaultplayercolors))
+                       if(player.clientcolors != stof(autocvar_sv_defaultplayercolors))
+                               setcolor(player, stof(autocvar_sv_defaultplayercolors));
+}
+
+
+/** Called when a client spawns in the server */
+void PutClientInServer(entity this)
+{
+       if (IS_BOT_CLIENT(this)) {
+               TRANSMUTE(Player, this);
+       } else if (IS_REAL_CLIENT(this)) {
+               msg_entity = this;
+               WriteByte(MSG_ONE, SVC_SETVIEW);
+               WriteEntity(MSG_ONE, this);
+       }
+       if (gameover) {
+               TRANSMUTE(Observer, this);
+       }
+
+       SetSpectatee(this, NULL);
+
+       // reset player keys
+       this.itemkeys = 0;
+
+       MUTATOR_CALLHOOK(PutClientInServer, this);
+
+       if (IS_OBSERVER(this)) {
+               PutObserverInServer(this);
+       } else if (IS_PLAYER(this)) {
+               if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE);
+
+               PlayerState_attach(this);
+               accuracy_resend(this);
+
+               if (this.team < 0)
+                       JoinBestTeam(this, false, true);
+
+               entity spot = SelectSpawnPoint(this, false);
+               if (!spot) {
+                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_NOSPAWNS);
+                       return; // spawn failed
+               }
+
+               TRANSMUTE(Player, this);
+
+               this.wasplayer = true;
+               this.iscreature = true;
+               this.teleportable = TELEPORT_NORMAL;
+               this.damagedbycontents = true;
+               set_movetype(this, MOVETYPE_WALK);
+               this.solid = SOLID_SLIDEBOX;
+               this.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID;
+               if (autocvar_g_playerclip_collisions)
+                       this.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP;
+               if (IS_BOT_CLIENT(this) && autocvar_g_botclip_collisions)
+                       this.dphitcontentsmask |= DPCONTENTS_BOTCLIP;
+               this.frags = FRAGS_PLAYER;
+               if (INDEPENDENT_PLAYERS) MAKE_INDEPENDENT_PLAYER(this);
+               this.flags = FL_CLIENT | FL_PICKUPITEMS;
+               if (autocvar__notarget)
+                       this.flags |= FL_NOTARGET;
+               this.takedamage = DAMAGE_AIM;
+               this.effects = EF_TELEPORT_BIT | EF_RESTARTANIM_BIT;
+               this.dmg = 2; // WTF
+
+               if (warmup_stage) {
+                       this.ammo_shells = warmup_start_ammo_shells;
+                       this.ammo_nails = warmup_start_ammo_nails;
+                       this.ammo_rockets = warmup_start_ammo_rockets;
+                       this.ammo_cells = warmup_start_ammo_cells;
+                       this.ammo_plasma = warmup_start_ammo_plasma;
+                       this.ammo_fuel = warmup_start_ammo_fuel;
+                       this.health = warmup_start_health;
+                       this.armorvalue = warmup_start_armorvalue;
+                       this.weapons = WARMUP_START_WEAPONS;
+               } else {
+                       this.ammo_shells = start_ammo_shells;
+                       this.ammo_nails = start_ammo_nails;
+                       this.ammo_rockets = start_ammo_rockets;
+                       this.ammo_cells = start_ammo_cells;
+                       this.ammo_plasma = start_ammo_plasma;
+                       this.ammo_fuel = start_ammo_fuel;
+                       this.health = start_health;
+                       this.armorvalue = start_armorvalue;
+                       this.weapons = start_weapons;
+               }
+               SetSpectatee_status(this, 0);
+
+               this.superweapons_finished = (this.weapons & WEPSET_SUPERWEAPONS) ? time + autocvar_g_balance_superweapons_time : 0;
+
+               this.items = start_items;
+
+               this.spawnshieldtime = time + autocvar_g_spawnshieldtime;
+               this.pauserotarmor_finished = time + autocvar_g_balance_pause_armor_rot_spawn;
+               this.pauserothealth_finished = time + autocvar_g_balance_pause_health_rot_spawn;
+               this.pauserotfuel_finished = time + autocvar_g_balance_pause_fuel_rot_spawn;
+               this.pauseregen_finished = time + autocvar_g_balance_pause_health_regen_spawn;
+               // extend the pause of rotting if client was reset at the beginning of the countdown
+               if (!autocvar_sv_ready_restart_after_countdown && time < game_starttime) { // TODO why is this cvar NOTted?
+                       float f = game_starttime - time;
+                       this.spawnshieldtime += f;
+                       this.pauserotarmor_finished += f;
+                       this.pauserothealth_finished += f;
+                       this.pauseregen_finished += f;
+               }
+               this.damageforcescale = 2;
+               this.death_time = 0;
+               this.respawn_flags = 0;
+               this.respawn_time = 0;
+               this.stat_respawn_time = 0;
+               this.scale = autocvar_sv_player_scale;
+               this.fade_time = 0;
+               this.pain_frame = 0;
+               this.pain_finished = 0;
+               this.pushltime = 0;
+               setthink(this, func_null); // players have no think function
+               this.nextthink = 0;
+               this.dmg_team = 0;
+               this.ballistics_density = autocvar_g_ballistics_density_player;
+
+               this.deadflag = DEAD_NO;
+
+               this.angles = spot.angles;
+               this.angles_z = 0; // never spawn tilted even if the spot says to
+               if (IS_BOT_CLIENT(this))
+                       this.v_angle = this.angles;
+               this.fixangle = true; // turn this way immediately
+               this.oldvelocity = this.velocity = '0 0 0';
+               this.avelocity = '0 0 0';
+               this.punchangle = '0 0 0';
+               this.punchvector = '0 0 0';
+
+               this.strength_finished = 0;
+               this.invincible_finished = 0;
+               this.fire_endtime = -1;
+               this.revival_time = 0;
+               this.air_finished = time + 12;
+
+               entity spawnevent = new_pure(spawnevent);
+               spawnevent.owner = this;
+               Net_LinkEntity(spawnevent, false, 0.5, SpawnEvent_Send);
+
+               // Cut off any still running player sounds.
+               stopsound(this, CH_PLAYER_SINGLE);
+
+               this.model = "";
+               FixPlayermodel(this);
+               this.drawonlytoclient = NULL;
+
+               this.crouch = false;
+               this.view_ofs = STAT(PL_VIEW_OFS, NULL);
+               setsize(this, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL));
+               this.spawnorigin = spot.origin;
+               setorigin(this, spot.origin + '0 0 1' * (1 - this.mins.z - 24));
+               // don't reset back to last position, even if new position is stuck in solid
+               this.oldorigin = this.origin;
+               this.prevorigin = this.origin;
+               this.lastteleporttime = time; // prevent insane speeds due to changing origin
+               if(this.conveyor)
+                       IL_REMOVE(g_conveyed, this);
+               this.conveyor = NULL; // prevent conveyors at the previous location from moving a freshly spawned player
+               this.hud = HUD_NORMAL;
+
+               this.event_damage = PlayerDamage;
+
+               if(!this.bot_attack)
+                       IL_PUSH(g_bot_targets, this);
+               this.bot_attack = true;
+               this.monster_attack = true;
+
+               PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_JUMP(this) = PHYS_INPUT_BUTTON_ATCK2(this) = false;
+
+               if (this.killcount == FRAGS_SPECTATOR) {
+                       PlayerScore_Clear(this);
+                       this.killcount = 0;
+               }
+
+               for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+               {
+                       CL_SpawnWeaponentity(this, weaponentities[slot]);
+               }
+               this.alpha = default_player_alpha;
+               this.colormod = '1 1 1' * autocvar_g_player_brightness;
+               this.exteriorweaponentity.alpha = default_weapon_alpha;
+
+               this.speedrunning = false;
+
+               target_voicescript_clear(this);
+
+               // reset fields the weapons may use
+               FOREACH(Weapons, true, LAMBDA(
+                       it.wr_resetplayer(it, this);
+                       // reload all reloadable weapons
+                       if (it.spawnflags & WEP_FLAG_RELOADABLE) {
+                               this.weapon_load[it.m_id] = it.reloading_ammo;
+                       }
+               ));
+
+               {
+                       string s = spot.target;
+                       spot.target = string_null;
+                       SUB_UseTargets(spot, this, NULL);
+                       spot.target = s;
+               }
+
+               Unfreeze(this);
+
+               MUTATOR_CALLHOOK(PlayerSpawn, this, spot);
+
+               if (autocvar_spawn_debug)
+               {
+                       sprint(this, strcat("spawnpoint origin:  ", vtos(spot.origin), "\n"));
+                       delete(spot); // usefull for checking if there are spawnpoints, that let drop through the floor
+               }
+
+               PS(this).m_switchweapon = w_getbestweapon(this);
+               this.cnt = -1; // W_LastWeapon will not complain
+               PS(this).m_weapon = WEP_Null;
+               this.weaponname = "";
+               PS(this).m_switchingweapon = WEP_Null;
+
+               if (!warmup_stage && !this.alivetime)
+                       this.alivetime = time;
+
+               antilag_clear(this, CS(this));
+       }
+}
+
+void ClientInit_misc(entity this);
+
+.float ebouncefactor, ebouncestop; // electro's values
+// TODO do we need all these fields, or should we stop autodetecting runtime
+// changes and just have a console command to update this?
+bool ClientInit_SendEntity(entity this, entity to, int sf)
+{
+       WriteHeader(MSG_ENTITY, _ENT_CLIENT_INIT);
+       return = true;
+       msg_entity = to;
+       // MSG_INIT replacement
+       // TODO: make easier to use
+       Registry_send_all();
+       W_PROP_reload(MSG_ONE, to);
+       ClientInit_misc(this);
+       MUTATOR_CALLHOOK(Ent_Init);
+}
+void ClientInit_misc(entity this)
+{
+       int channel = MSG_ONE;
+       WriteHeader(channel, ENT_CLIENT_INIT);
+       WriteByte(channel, g_nexball_meter_period * 32);
+       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[0]));
+       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[1]));
+       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[2]));
+       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[3]));
+       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[0]));
+       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[1]));
+       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[2]));
+       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[3]));
+
+       if(sv_foginterval && world.fog != "")
+               WriteString(channel, world.fog);
+       else
+               WriteString(channel, "");
+       WriteByte(channel, this.count * 255.0); // g_balance_armor_blockpercent
+       WriteByte(channel, serverflags);
+       WriteCoord(channel, autocvar_g_trueaim_minrange);
+}
+
+void ClientInit_CheckUpdate(entity this)
+{
+       this.nextthink = time;
+       if(this.count != autocvar_g_balance_armor_blockpercent)
+       {
+               this.count = autocvar_g_balance_armor_blockpercent;
+               this.SendFlags |= 1;
+       }
+}
+
+void ClientInit_Spawn()
+{
+       entity e = new_pure(clientinit);
+       setthink(e, ClientInit_CheckUpdate);
+       Net_LinkEntity(e, false, 0, ClientInit_SendEntity);
+
+       ClientInit_CheckUpdate(e);
+}
+
+/*
+=============
+SetNewParms
+=============
+*/
+void SetNewParms ()
+{
+       // initialize parms for a new player
+       parm1 = -(86400 * 366);
+
+       MUTATOR_CALLHOOK(SetNewParms);
+}
+
+/*
+=============
+SetChangeParms
+=============
+*/
+void SetChangeParms (entity this)
+{
+       // save parms for level change
+       parm1 = this.parm_idlesince - time;
+
+       MUTATOR_CALLHOOK(SetChangeParms);
+}
+
+/*
+=============
+DecodeLevelParms
+=============
+*/
+void DecodeLevelParms(entity this)
+{
+       // load parms
+       this.parm_idlesince = parm1;
+       if (this.parm_idlesince == -(86400 * 366))
+               this.parm_idlesince = time;
+
+       // whatever happens, allow 60 seconds of idling directly after connect for map loading
+       this.parm_idlesince = max(this.parm_idlesince, time - sv_maxidle + 60);
+
+       MUTATOR_CALLHOOK(DecodeLevelParms);
+}
+
+/*
+=============
+ClientKill
+
+Called when a client types 'kill' in the console
+=============
+*/
+
+.float clientkill_nexttime;
+void ClientKill_Now_TeamChange(entity this)
+{
+       if(this.killindicator_teamchange == -1)
+       {
+               JoinBestTeam( this, false, true );
+       }
+       else if(this.killindicator_teamchange == -2)
+       {
+               if(blockSpectators)
+                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
+               PutObserverInServer(this);
+       }
+       else
+               SV_ChangeTeam(this, this.killindicator_teamchange - 1);
+       this.killindicator_teamchange = 0;
+}
+
+void ClientKill_Now(entity this)
+{
+       if(this.vehicle)
+       {
+           vehicles_exit(this.vehicle, VHEF_RELEASE);
+           if(!this.killindicator_teamchange)
+           {
+            this.vehicle_health = -1;
+            Damage(this, this, this, 1 , DEATH_KILL.m_id, this.origin, '0 0 0');
+           }
+       }
+
+       if(this.killindicator && !wasfreed(this.killindicator))
+               delete(this.killindicator);
+
+       this.killindicator = NULL;
+
+       if(this.killindicator_teamchange)
+               ClientKill_Now_TeamChange(this);
+
+       if(!IS_SPEC(this) && !IS_OBSERVER(this))
+               Damage(this, this, this, 100000, DEATH_KILL.m_id, this.origin, '0 0 0');
+
+       // now I am sure the player IS dead
+}
+void KillIndicator_Think(entity this)
+{
+       if (gameover)
+       {
+               this.owner.killindicator = NULL;
+               delete(this);
+               return;
+       }
+
+       if (this.owner.alpha < 0 && !this.owner.vehicle)
+       {
+               this.owner.killindicator = NULL;
+               delete(this);
+               return;
+       }
+
+       if(this.cnt <= 0)
+       {
+               ClientKill_Now(this.owner);
+               return;
+       }
+    else if(g_cts && this.health == 1) // health == 1 means that it's silent
+    {
+        this.nextthink = time + 1;
+        this.cnt -= 1;
+    }
+       else
+       {
+               if(this.cnt <= 10)
+                       setmodel(this, MDL_NUM(this.cnt));
+               if(IS_REAL_CLIENT(this.owner))
+               {
+                       if(this.cnt <= 10)
+                               { Send_Notification(NOTIF_ONE, this.owner, MSG_ANNCE, Announcer_PickNumber(CNT_KILL, this.cnt)); }
+               }
+               this.nextthink = time + 1;
+               this.cnt -= 1;
+       }
+}
+
+float clientkilltime;
+void ClientKill_TeamChange (entity this, float targetteam) // 0 = don't change, -1 = auto, -2 = spec
+{
+       float killtime;
+       float starttime;
+
+       if (gameover)
+               return;
+
+       killtime = autocvar_g_balance_kill_delay;
+
+       if(g_race_qualifying || g_cts)
+               killtime = 0;
+
+    if(MUTATOR_CALLHOOK(ClientKill, this, killtime))
+       return;
+
+       this.killindicator_teamchange = targetteam;
+
+    if(!this.killindicator)
+       {
+               if(!IS_DEAD(this))
+               {
+                       killtime = max(killtime, this.clientkill_nexttime - time);
+                       this.clientkill_nexttime = time + killtime + autocvar_g_balance_kill_antispam;
+               }
+
+               if(killtime <= 0 || !IS_PLAYER(this) || IS_DEAD(this))
+               {
+                       ClientKill_Now(this);
+               }
+               else
+               {
+                       starttime = max(time, clientkilltime);
+
+                       this.killindicator = spawn();
+                       this.killindicator.owner = this;
+                       this.killindicator.scale = 0.5;
+                       setattachment(this.killindicator, this, "");
+                       setorigin(this.killindicator, '0 0 52');
+                       setthink(this.killindicator, KillIndicator_Think);
+                       this.killindicator.nextthink = starttime + (this.lip) * 0.05;
+                       clientkilltime = max(clientkilltime, this.killindicator.nextthink + 0.05);
+                       this.killindicator.cnt = ceil(killtime);
+                       this.killindicator.count = bound(0, ceil(killtime), 10);
+                       //sprint(this, strcat("^1You'll be dead in ", ftos(this.killindicator.cnt), " seconds\n"));
+
+                       IL_EACH(g_clones, it.enemy == this && !(it.effects & CSQCMODEL_EF_RESPAWNGHOST),
+                       {
+                               it.killindicator = spawn();
+                               it.killindicator.owner = it;
+                               it.killindicator.scale = 0.5;
+                               setattachment(it.killindicator, it, "");
+                               setorigin(it.killindicator, '0 0 52');
+                               setthink(it.killindicator, KillIndicator_Think);
+                               it.killindicator.nextthink = starttime + (it.lip) * 0.05;
+                               //clientkilltime = max(clientkilltime, it.killindicator.nextthink + 0.05);
+                               it.killindicator.cnt = ceil(killtime);
+                       });
+                       this.lip = 0;
+               }
+       }
+       if(this.killindicator)
+       {
+               if(targetteam == 0) // just die
+               {
+                       this.killindicator.colormod = '0 0 0';
+                       if(IS_REAL_CLIENT(this))
+                       if(this.killindicator.cnt > 0)
+                               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_TEAMCHANGE_SUICIDE, this.killindicator.cnt);
+               }
+               else if(targetteam == -1) // auto
+               {
+                       this.killindicator.colormod = '0 1 0';
+                       if(IS_REAL_CLIENT(this))
+                       if(this.killindicator.cnt > 0)
+                               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_TEAMCHANGE_AUTO, this.killindicator.cnt);
+               }
+               else if(targetteam == -2) // spectate
+               {
+                       this.killindicator.colormod = '0.5 0.5 0.5';
+                       if(IS_REAL_CLIENT(this))
+                       if(this.killindicator.cnt > 0)
+                               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_TEAMCHANGE_SPECTATE, this.killindicator.cnt);
+               }
+               else
+               {
+                       this.killindicator.colormod = Team_ColorRGB(targetteam);
+                       if(IS_REAL_CLIENT(this))
+                       if(this.killindicator.cnt > 0)
+                               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, APP_TEAM_NUM(targetteam, CENTER_TEAMCHANGE), this.killindicator.cnt);
+               }
+       }
+
+}
+
+void ClientKill (entity this)
+{
+       if(gameover) return;
+       if(this.player_blocked) return;
+       if(STAT(FROZEN, this)) return;
+
+       ClientKill_TeamChange(this, 0);
+}
+
+void FixClientCvars(entity e)
+{
+       // send prediction settings to the client
+       stuffcmd(e, "\nin_bindmap 0 0\n");
+       if(autocvar_g_antilag == 3) // client side hitscan
+               stuffcmd(e, "cl_cmd settemp cl_prydoncursor_notrace 0\n");
+       if(autocvar_sv_gentle)
+               stuffcmd(e, "cl_cmd settemp cl_gentle 1\n");
+
+       MUTATOR_CALLHOOK(FixClientCvars, e);
+}
+
+float PlayerInIDList(entity p, string idlist)
+{
+       float n, i;
+       string s;
+
+       // NOTE: we do NOT check crypto_idfp_signed here, an unsigned ID is fine too for this
+       if (!p.crypto_idfp)
+               return 0;
+
+       // this function allows abbreviated player IDs too!
+       n = tokenize_console(idlist);
+       for(i = 0; i < n; ++i)
+       {
+               s = argv(i);
+               if(s == substring(p.crypto_idfp, 0, strlen(s)))
+                       return 1;
+       }
+
+       return 0;
+}
+
+#ifdef DP_EXT_PRECONNECT
+/*
+=============
+ClientPreConnect
+
+Called once (not at each match start) when a client begins a connection to the server
+=============
+*/
+void ClientPreConnect ()
+{ENGINE_EVENT();
+       if(autocvar_sv_eventlog)
+       {
+               GameLogEcho(sprintf(":connect:%d:%d:%s",
+                       this.playerid,
+                       etof(this),
+                       ((IS_REAL_CLIENT(this)) ? this.netaddress : "bot")
+               ));
+       }
+}
+#endif
+
+/**
+=============
+ClientConnect
+
+Called when a client connects to the server
+=============
+*/
+void ClientConnect(entity this)
+{
+       if (Ban_MaybeEnforceBanOnce(this)) return;
+       assert(!IS_CLIENT(this), return);
+       this.flags |= FL_CLIENT;
+       assert(player_count >= 0, player_count = 0);
+
+#ifdef WATERMARK
+       Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_WATERMARK, WATERMARK);
+#endif
+       this.version_nagtime = time + 10 + random() * 10;
+       TRANSMUTE(Client, this);
+
+       // identify the right forced team
+       if (autocvar_g_campaign)
+       {
+               if (IS_REAL_CLIENT(this)) // only players, not bots
+               {
+                       switch (autocvar_g_campaign_forceteam)
+                       {
+                               case 1: this.team_forced = NUM_TEAM_1; break;
+                               case 2: this.team_forced = NUM_TEAM_2; break;
+                               case 3: this.team_forced = NUM_TEAM_3; break;
+                               case 4: this.team_forced = NUM_TEAM_4; break;
+                               default: this.team_forced = 0;
+                       }
+               }
+       }
+       else if (PlayerInIDList(this, autocvar_g_forced_team_red))    this.team_forced = NUM_TEAM_1;
+       else if (PlayerInIDList(this, autocvar_g_forced_team_blue))   this.team_forced = NUM_TEAM_2;
+       else if (PlayerInIDList(this, autocvar_g_forced_team_yellow)) this.team_forced = NUM_TEAM_3;
+       else if (PlayerInIDList(this, autocvar_g_forced_team_pink))   this.team_forced = NUM_TEAM_4;
+       else switch (autocvar_g_forced_team_otherwise)
+       {
+               default: this.team_forced = 0; break;
+               case "red": this.team_forced = NUM_TEAM_1; break;
+               case "blue": this.team_forced = NUM_TEAM_2; break;
+               case "yellow": this.team_forced = NUM_TEAM_3; break;
+               case "pink": this.team_forced = NUM_TEAM_4; break;
+               case "spectate":
+               case "spectator":
+                       this.team_forced = -1;
+                       break;
+       }
+       if (!teamplay && this.team_forced > 0) this.team_forced = 0;
+
+    {
+        int id = this.playerid;
+        this.playerid = 0; // silent
+           JoinBestTeam(this, false, false); // if the team number is valid, keep it
+           this.playerid = id;
+    }
+
+       if (autocvar_sv_spectate || autocvar_g_campaign || this.team_forced < 0) {
+               TRANSMUTE(Observer, this);
+       } else {
+               if (!teamplay || autocvar_g_balance_teams) {
+                       TRANSMUTE(Player, this);
+                       campaign_bots_may_start = true;
+               } else {
+                       TRANSMUTE(Observer, this); // do it anyway
+               }
+       }
+
+       PlayerStats_GameReport_AddEvent(sprintf("kills-%d", this.playerid));
+
+       // always track bots, don't ask for cl_allow_uidtracking
+    if (IS_BOT_CLIENT(this)) PlayerStats_GameReport_AddPlayer(this);
+
+       if (autocvar_sv_eventlog)
+               GameLogEcho(strcat(":join:", ftos(this.playerid), ":", ftos(etof(this)), ":", ((IS_REAL_CLIENT(this)) ? this.netaddress : "bot"), ":", this.netname));
+
+       LogTeamchange(this.playerid, this.team, 1);
+
+       this.just_joined = true;  // stop spamming the eventlog with additional lines when the client connects
+
+       this.netname_previous = strzone(this.netname);
+
+       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((teamplay && IS_PLAYER(this)) ? APP_TEAM_ENT(this, INFO_JOIN_CONNECT_TEAM) : INFO_JOIN_CONNECT), this.netname);
+
+       stuffcmd(this, clientstuff, "\n");
+       stuffcmd(this, "cl_particles_reloadeffects\n"); // TODO do we still need this?
+
+       FixClientCvars(this);
+
+       // get version info from player
+       stuffcmd(this, "cmd clientversion $gameversion\n");
+
+       // notify about available teams
+       if (teamplay)
+       {
+               CheckAllowedTeams(this);
+               int t = 0;
+               if (c1 >= 0) t |= BIT(0);
+               if (c2 >= 0) t |= BIT(1);
+               if (c3 >= 0) t |= BIT(2);
+               if (c4 >= 0) t |= BIT(3);
+               stuffcmd(this, sprintf("set _teams_available %d\n", t));
+       }
+       else
+       {
+               stuffcmd(this, "set _teams_available 0\n");
+       }
+
+       bot_relinkplayerlist();
+
+       this.spectatortime = time;
+       if (blockSpectators)
+       {
+               Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
+       }
+
+       this.jointime = time;
+       this.allowed_timeouts = autocvar_sv_timeout_number;
+
+       if (IS_REAL_CLIENT(this))
+       {
+               if (!autocvar_g_campaign)
+               {
+                       this.motd_actived_time = -1;
+                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, getwelcomemessage(this));
+               }
+
+               if (g_weaponarena_weapons == WEPSET(TUBA))
+                       stuffcmd(this, "cl_cmd settemp chase_active 1\n");
+       }
+
+       if (!sv_foginterval && world.fog != "")
+               stuffcmd(this, strcat("\nfog ", world.fog, "\nr_fog_exp2 0\nr_drawfog 1\n"));
+
+       if (autocvar_sv_teamnagger && !(autocvar_bot_vs_human && AvailableTeams() == 2))
+               if (!g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts
+                       send_CSQC_teamnagger();
+
+       CSQCMODEL_AUTOINIT(this);
+
+       this.model_randomizer = random();
+
+       if (IS_REAL_CLIENT(this))
+               sv_notice_join(this);
+
+       IL_EACH(g_initforplayer, it.init_for_player, {
+               it.init_for_player(it, this);
+       });
+
+       MUTATOR_CALLHOOK(ClientConnect, this);
+}
+/*
+=============
+ClientDisconnect
+
+Called when a client disconnects from the server
+=============
+*/
+.entity chatbubbleentity;
+void ReadyCount();
+void ClientDisconnect(entity this)
+{
+       assert(IS_CLIENT(this), return);
+
+       PlayerStats_GameReport_FinalizePlayer(this);
+       if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE);
+       if (this.active_minigame) part_minigame(this);
+       if (IS_PLAYER(this)) Send_Effect(EFFECT_SPAWN_NEUTRAL, this.origin, '0 0 0', 1);
+
+       if (autocvar_sv_eventlog)
+               GameLogEcho(strcat(":part:", ftos(this.playerid)));
+
+       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_DISCONNECT, this.netname);
+
+       SetSpectatee(this, NULL);
+
+    MUTATOR_CALLHOOK(ClientDisconnect, this);
+
+       ClientState_detach(this);
+
+       Portal_ClearAll(this);
+
+       Unfreeze(this);
+
+       RemoveGrapplingHook(this);
+
+       // Here, everything has been done that requires this player to be a client.
+
+       this.flags &= ~FL_CLIENT;
+
+       if (this.chatbubbleentity) delete(this.chatbubbleentity);
+       if (this.killindicator) delete(this.killindicator);
+
+       WaypointSprite_PlayerGone(this);
+
+       bot_relinkplayerlist();
+
+       if (this.netname_previous) strunzone(this.netname_previous);
+       if (this.clientstatus) strunzone(this.clientstatus);
+       if (this.weaponorder_byimpulse) strunzone(this.weaponorder_byimpulse);
+       if (this.personal) delete(this.personal);
+
+       this.playerid = 0;
+       ReadyCount();
+       if (vote_called && IS_REAL_CLIENT(this)) VoteCount(false);
+}
+
+void ChatBubbleThink(entity this)
+{
+       this.nextthink = time;
+       if ((this.owner.alpha < 0) || this.owner.chatbubbleentity != this)
+       {
+               if(this.owner) // but why can that ever be NULL?
+                       this.owner.chatbubbleentity = NULL;
+               delete(this);
+               return;
+       }
+
+       this.mdl = "";
+
+       if ( !IS_DEAD(this.owner) && IS_PLAYER(this.owner) )
+       {
+               if ( this.owner.active_minigame )
+                       this.mdl = "models/sprites/minigame_busy.iqm";
+               else if (PHYS_INPUT_BUTTON_CHAT(this.owner))
+                       this.mdl = "models/misc/chatbubble.spr";
+       }
+
+       if ( this.model != this.mdl )
+               _setmodel(this, this.mdl);
+
+}
+
+void UpdateChatBubble(entity this)
+{
+       if (this.alpha < 0)
+               return;
+       // spawn a chatbubble entity if needed
+       if (!this.chatbubbleentity)
+       {
+               this.chatbubbleentity = new(chatbubbleentity);
+               this.chatbubbleentity.owner = this;
+               this.chatbubbleentity.exteriormodeltoclient = this;
+               setthink(this.chatbubbleentity, ChatBubbleThink);
+               this.chatbubbleentity.nextthink = time;
+               setmodel(this.chatbubbleentity, MDL_CHAT); // precision set below
+               //setorigin(this.chatbubbleentity, this.origin + '0 0 15' + this.maxs_z * '0 0 1');
+               setorigin(this.chatbubbleentity, '0 0 15' + this.maxs_z * '0 0 1');
+               setattachment(this.chatbubbleentity, this, "");  // sticks to moving player better, also conserves bandwidth
+               this.chatbubbleentity.mdl = this.chatbubbleentity.model;
+               //this.chatbubbleentity.model = "";
+               this.chatbubbleentity.effects = EF_LOWPRECISION;
+       }
+}
+
+
+// LordHavoc: this hack will be removed when proper _pants/_shirt layers are
+// added to the model skins
+/*void UpdateColorModHack()
+{
+       float c;
+       c = this.clientcolors & 15;
+       // LordHavoc: only bothering to support white, green, red, yellow, blue
+            if (!teamplay) this.colormod = '0 0 0';
+       else if (c ==  0) this.colormod = '1.00 1.00 1.00';
+       else if (c ==  3) this.colormod = '0.10 1.73 0.10';
+       else if (c ==  4) this.colormod = '1.73 0.10 0.10';
+       else if (c == 12) this.colormod = '1.22 1.22 0.10';
+       else if (c == 13) this.colormod = '0.10 0.10 1.73';
+       else this.colormod = '1 1 1';
+}*/
+
+void respawn(entity this)
+{
+       if(this.alpha >= 0 && autocvar_g_respawn_ghosts)
+       {
+               this.solid = SOLID_NOT;
+               this.takedamage = DAMAGE_NO;
+               set_movetype(this, MOVETYPE_FLY);
+               this.velocity = '0 0 1' * autocvar_g_respawn_ghosts_speed;
+               this.avelocity = randomvec() * autocvar_g_respawn_ghosts_speed * 3 - randomvec() * autocvar_g_respawn_ghosts_speed * 3;
+               this.effects |= CSQCMODEL_EF_RESPAWNGHOST;
+               Send_Effect(EFFECT_RESPAWN_GHOST, this.origin, '0 0 0', 1);
+               if(autocvar_g_respawn_ghosts_maxtime)
+                       SUB_SetFade (this, time + autocvar_g_respawn_ghosts_maxtime / 2 + random () * (autocvar_g_respawn_ghosts_maxtime - autocvar_g_respawn_ghosts_maxtime / 2), 1.5);
+       }
+
+       CopyBody(this, 1);
+
+       this.effects |= EF_NODRAW; // prevent another CopyBody
+       PutClientInServer(this);
+}
+
+void play_countdown(entity this, float finished, Sound samp)
+{
+    TC(Sound, samp);
+       if(IS_REAL_CLIENT(this))
+               if(floor(finished - time - frametime) != floor(finished - time))
+                       if(finished - time < 6)
+                               sound (this, CH_INFO, samp, VOL_BASE, ATTEN_NORM);
+}
+
+void player_powerups(entity this)
+{
+       // add a way to see what the items were BEFORE all of these checks for the mutator hook
+       int items_prev = this.items;
+
+       if((this.items & IT_USING_JETPACK) && !IS_DEAD(this) && !gameover)
+               this.modelflags |= MF_ROCKET;
+       else
+               this.modelflags &= ~MF_ROCKET;
+
+       this.effects &= ~(EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT | EF_FLAME | EF_NODEPTHTEST);
+
+       if((this.alpha < 0 || IS_DEAD(this)) && !this.vehicle) // don't apply the flags if the player is gibbed
+               return;
+
+       Fire_ApplyDamage(this);
+       Fire_ApplyEffect(this);
+
+       if (!g_instagib)
+       {
+               if (this.items & ITEM_Strength.m_itemid)
+               {
+                       play_countdown(this, this.strength_finished, SND_POWEROFF);
+                       this.effects = this.effects | (EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT);
+                       if (time > this.strength_finished)
+                       {
+                               this.items = this.items - (this.items & ITEM_Strength.m_itemid);
+                               //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERDOWN_STRENGTH, this.netname);
+                               Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERDOWN_STRENGTH);
+                       }
+               }
+               else
+               {
+                       if (time < this.strength_finished)
+                       {
+                               this.items = this.items | ITEM_Strength.m_itemid;
+                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_STRENGTH, this.netname);
+                               Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERUP_STRENGTH);
+                       }
+               }
+               if (this.items & ITEM_Shield.m_itemid)
+               {
+                       play_countdown(this, this.invincible_finished, SND_POWEROFF);
+                       this.effects = this.effects | (EF_RED | EF_ADDITIVE | EF_FULLBRIGHT);
+                       if (time > this.invincible_finished)
+                       {
+                               this.items = this.items - (this.items & ITEM_Shield.m_itemid);
+                               //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERDOWN_SHIELD, this.netname);
+                               Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERDOWN_SHIELD);
+                       }
+               }
+               else
+               {
+                       if (time < this.invincible_finished)
+                       {
+                               this.items = this.items | ITEM_Shield.m_itemid;
+                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_SHIELD, this.netname);
+                               Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERUP_SHIELD);
+                       }
+               }
+               if (this.items & IT_SUPERWEAPON)
+               {
+                       if (!(this.weapons & WEPSET_SUPERWEAPONS))
+                       {
+                               this.superweapons_finished = 0;
+                               this.items = this.items - (this.items & IT_SUPERWEAPON);
+                               //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_LOST, this.netname);
+                               Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_SUPERWEAPON_LOST);
+                       }
+                       else if (this.items & IT_UNLIMITED_SUPERWEAPONS)
+                       {
+                               // don't let them run out
+                       }
+                       else
+                       {
+                               play_countdown(this, this.superweapons_finished, SND_POWEROFF);
+                               if (time > this.superweapons_finished)
+                               {
+                                       this.items = this.items - (this.items & IT_SUPERWEAPON);
+                                       this.weapons &= ~WEPSET_SUPERWEAPONS;
+                                       //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_BROKEN, this.netname);
+                                       Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_SUPERWEAPON_BROKEN);
+                               }
+                       }
+               }
+               else if(this.weapons & WEPSET_SUPERWEAPONS)
+               {
+                       if (time < this.superweapons_finished || (this.items & IT_UNLIMITED_SUPERWEAPONS))
+                       {
+                               this.items = this.items | IT_SUPERWEAPON;
+                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_PICKUP, this.netname);
+                               Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_SUPERWEAPON_PICKUP);
+                       }
+                       else
+                       {
+                               this.superweapons_finished = 0;
+                               this.weapons &= ~WEPSET_SUPERWEAPONS;
+                       }
+               }
+               else
+               {
+                       this.superweapons_finished = 0;
+               }
+       }
+
+       if(autocvar_g_nodepthtestplayers)
+               this.effects = this.effects | EF_NODEPTHTEST;
+
+       if(autocvar_g_fullbrightplayers)
+               this.effects = this.effects | EF_FULLBRIGHT;
+
+       if (time >= game_starttime)
+       if (time < this.spawnshieldtime)
+               this.effects = this.effects | (EF_ADDITIVE | EF_FULLBRIGHT);
+
+       MUTATOR_CALLHOOK(PlayerPowerups, this, items_prev);
+}
+
+float CalcRegen(float current, float stable, float regenfactor, float regenframetime)
+{
+       if(current > stable)
+               return current;
+       else if(current > stable - 0.25) // when close enough, "snap"
+               return stable;
+       else
+               return min(stable, current + (stable - current) * regenfactor * regenframetime);
+}
+
+float CalcRot(float current, float stable, float rotfactor, float rotframetime)
+{
+       if(current < stable)
+               return current;
+       else if(current < stable + 0.25) // when close enough, "snap"
+               return stable;
+       else
+               return max(stable, current + (stable - current) * rotfactor * rotframetime);
+}
+
+float CalcRotRegen(float current, float regenstable, float regenfactor, float regenlinear, float regenframetime, float rotstable, float rotfactor, float rotlinear, float rotframetime, float limit)
+{
+       if(current > rotstable)
+       {
+               if(rotframetime > 0)
+               {
+                       current = CalcRot(current, rotstable, rotfactor, rotframetime);
+                       current = max(rotstable, current - rotlinear * rotframetime);
+               }
+       }
+       else if(current < regenstable)
+       {
+               if(regenframetime > 0)
+               {
+                       current = CalcRegen(current, regenstable, regenfactor, regenframetime);
+                       current = min(regenstable, current + regenlinear * regenframetime);
+               }
+       }
+
+       if(current > limit)
+               current = limit;
+
+       return current;
+}
+
+void player_regen(entity this)
+{
+       float max_mod, regen_mod, rot_mod, limit_mod;
+       max_mod = regen_mod = rot_mod = limit_mod = 1;
+
+       float regen_health = autocvar_g_balance_health_regen;
+       float regen_health_linear = autocvar_g_balance_health_regenlinear;
+       float regen_health_rot = autocvar_g_balance_health_rot;
+       float regen_health_rotlinear = autocvar_g_balance_health_rotlinear;
+       float regen_health_stable = autocvar_g_balance_health_regenstable;
+       float regen_health_rotstable = autocvar_g_balance_health_rotstable;
+       bool mutator_returnvalue = MUTATOR_CALLHOOK(PlayerRegen, this, max_mod, regen_mod, rot_mod, limit_mod, regen_health, regen_health_linear, regen_health_rot,
+               regen_health_rotlinear, regen_health_stable, regen_health_rotstable);
+       max_mod = M_ARGV(1, float);
+       regen_mod = M_ARGV(2, float);
+       rot_mod = M_ARGV(3, float);
+       limit_mod = M_ARGV(4, float);
+       regen_health = M_ARGV(5, float);
+       regen_health_linear = M_ARGV(6, float);
+       regen_health_rot = M_ARGV(7, float);
+       regen_health_rotlinear = M_ARGV(8, float);
+       regen_health_stable = M_ARGV(9, float);
+       regen_health_rotstable = M_ARGV(10, float);
+
+
+       if(!mutator_returnvalue)
+       if(!STAT(FROZEN, this))
+       {
+               float mina, maxa, limith, limita;
+               maxa = autocvar_g_balance_armor_rotstable;
+               mina = autocvar_g_balance_armor_regenstable;
+               limith = autocvar_g_balance_health_limit;
+               limita = autocvar_g_balance_armor_limit;
+
+               regen_health_rotstable = regen_health_rotstable * max_mod;
+               regen_health_stable = regen_health_stable * max_mod;
+               limith = limith * limit_mod;
+               limita = limita * limit_mod;
+
+               this.armorvalue = CalcRotRegen(this.armorvalue, mina, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear, regen_mod * frametime * (time > this.pauseregen_finished), maxa, autocvar_g_balance_armor_rot, autocvar_g_balance_armor_rotlinear, rot_mod * frametime * (time > this.pauserotarmor_finished), limita);
+               this.health = CalcRotRegen(this.health, regen_health_stable, regen_health, regen_health_linear, regen_mod * frametime * (time > this.pauseregen_finished), regen_health_rotstable, regen_health_rot, regen_health_rotlinear, rot_mod * frametime * (time > this.pauserothealth_finished), limith);
+       }
+
+       // if player rotted to death...  die!
+       // check this outside above checks, as player may still be able to rot to death
+       if(this.health < 1)
+       {
+               if(this.vehicle)
+                       vehicles_exit(this.vehicle, VHEF_RELEASE);
+               if(this.event_damage)
+                       this.event_damage(this, this, this, 1, DEATH_ROT.m_id, this.origin, '0 0 0');
+       }
+
+       if (!(this.items & IT_UNLIMITED_WEAPON_AMMO))
+       {
+               float minf, maxf, limitf;
+
+               maxf = autocvar_g_balance_fuel_rotstable;
+               minf = autocvar_g_balance_fuel_regenstable;
+               limitf = autocvar_g_balance_fuel_limit;
+
+               this.ammo_fuel = CalcRotRegen(this.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, frametime * (time > this.pauseregen_finished) * ((this.items & ITEM_JetpackRegen.m_itemid) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > this.pauserotfuel_finished), limitf);
+       }
+}
+
+bool zoomstate_set;
+void SetZoomState(entity this, float z)
+{
+       if(z != this.zoomstate)
+       {
+               this.zoomstate = z;
+               ClientData_Touch(this);
+       }
+       zoomstate_set = true;
+}
+
+void GetPressedKeys(entity this)
+{
+       MUTATOR_CALLHOOK(GetPressedKeys, this);
+       int keys = this.pressedkeys;
+       keys = BITSET(keys, KEY_FORWARD,        this.movement.x > 0);
+       keys = BITSET(keys, KEY_BACKWARD,       this.movement.x < 0);
+       keys = BITSET(keys, KEY_RIGHT,          this.movement.y > 0);
+       keys = BITSET(keys, KEY_LEFT,           this.movement.y < 0);
+
+       keys = BITSET(keys, KEY_JUMP,           PHYS_INPUT_BUTTON_JUMP(this));
+       keys = BITSET(keys, KEY_CROUCH,         PHYS_INPUT_BUTTON_CROUCH(this));
+       keys = BITSET(keys, KEY_ATCK,           PHYS_INPUT_BUTTON_ATCK(this));
+       keys = BITSET(keys, KEY_ATCK2,          PHYS_INPUT_BUTTON_ATCK2(this));
+       this.pressedkeys = keys;
+}
+
+/*
+======================
+spectate mode routines
+======================
+*/
+
+void SpectateCopy(entity this, entity spectatee)
+{
+    TC(Client, this); TC(Client, spectatee);
+
+       MUTATOR_CALLHOOK(SpectateCopy, spectatee, this);
+       PS(this) = PS(spectatee);
+       this.armortype = spectatee.armortype;
+       this.armorvalue = spectatee.armorvalue;
+       this.ammo_cells = spectatee.ammo_cells;
+       this.ammo_plasma = spectatee.ammo_plasma;
+       this.ammo_shells = spectatee.ammo_shells;
+       this.ammo_nails = spectatee.ammo_nails;
+       this.ammo_rockets = spectatee.ammo_rockets;
+       this.ammo_fuel = spectatee.ammo_fuel;
+       this.clip_load = spectatee.clip_load;
+       this.clip_size = spectatee.clip_size;
+       this.effects = spectatee.effects & EFMASK_CHEAP; // eat performance
+       this.health = spectatee.health;
+       this.impulse = 0;
+       this.items = spectatee.items;
+       this.last_pickup = spectatee.last_pickup;
+       this.hit_time = spectatee.hit_time;
+       this.strength_finished = spectatee.strength_finished;
+       this.invincible_finished = spectatee.invincible_finished;
+       this.pressedkeys = spectatee.pressedkeys;
+       this.weapons = spectatee.weapons;
+       this.vortex_charge = spectatee.vortex_charge;
+       this.vortex_chargepool_ammo = spectatee.vortex_chargepool_ammo;
+       this.hagar_load = spectatee.hagar_load;
+       this.arc_heat_percent = spectatee.arc_heat_percent;
+       this.minelayer_mines = spectatee.minelayer_mines;
+       this.punchangle = spectatee.punchangle;
+       this.view_ofs = spectatee.view_ofs;
+       this.velocity = spectatee.velocity;
+       this.dmg_take = spectatee.dmg_take;
+       this.dmg_save = spectatee.dmg_save;
+       this.dmg_inflictor = spectatee.dmg_inflictor;
+       this.v_angle = spectatee.v_angle;
+       this.angles = spectatee.v_angle;
+       STAT(FROZEN, this) = STAT(FROZEN, spectatee);
+       this.revive_progress = spectatee.revive_progress;
+       if(!PHYS_INPUT_BUTTON_USE(this) && STAT(CAMERA_SPECTATOR, this) != 2)
+               this.fixangle = true;
+       setorigin(this, spectatee.origin);
+       setsize(this, spectatee.mins, spectatee.maxs);
+       SetZoomState(this, spectatee.zoomstate);
+
+    anticheat_spectatecopy(this, spectatee);
+       this.hud = spectatee.hud;
+       if(spectatee.vehicle)
+    {
+       this.angles = spectatee.v_angle;
+
+        //this.fixangle = false;
+        //this.velocity = spectatee.vehicle.velocity;
+        this.vehicle_health = spectatee.vehicle_health;
+        this.vehicle_shield = spectatee.vehicle_shield;
+        this.vehicle_energy = spectatee.vehicle_energy;
+        this.vehicle_ammo1 = spectatee.vehicle_ammo1;
+        this.vehicle_ammo2 = spectatee.vehicle_ammo2;
+        this.vehicle_reload1 = spectatee.vehicle_reload1;
+        this.vehicle_reload2 = spectatee.vehicle_reload2;
+
+        //msg_entity = this;
+
+       // WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
+            //WriteAngle(MSG_ONE,  spectatee.v_angle.x);
+           // WriteAngle(MSG_ONE,  spectatee.v_angle.y);
+           // WriteAngle(MSG_ONE,  spectatee.v_angle.z);
+
+        //WriteByte (MSG_ONE, SVC_SETVIEW);
+        //    WriteEntity(MSG_ONE, this);
+        //makevectors(spectatee.v_angle);
+        //setorigin(this, spectatee.origin - v_forward * 400 + v_up * 300);*/
+    }
+}
+
+bool SpectateUpdate(entity this)
+{
+       if(!this.enemy)
+           return false;
+
+       if(!IS_PLAYER(this.enemy) || this == this.enemy)
+       {
+               SetSpectatee(this, NULL);
+               return false;
+       }
+
+       SpectateCopy(this, this.enemy);
+
+       return true;
+}
+
+bool SpectateSet(entity this)
+{
+       if(!IS_PLAYER(this.enemy))
+               return false;
+
+       ClientData_Touch(this.enemy);
+
+       msg_entity = this;
+       WriteByte(MSG_ONE, SVC_SETVIEW);
+       WriteEntity(MSG_ONE, this.enemy);
+       set_movetype(this, MOVETYPE_NONE);
+       accuracy_resend(this);
+
+       if(!SpectateUpdate(this))
+               PutObserverInServer(this);
+
+       return true;
+}
+
+void SetSpectatee_status(entity this, int spectatee_num)
+{
+       int oldspectatee_status = this.spectatee_status;
+       this.spectatee_status = spectatee_num;
+
+       if (this.spectatee_status != oldspectatee_status)
+       {
+               ClientData_Touch(this);
+               if (g_race || g_cts) race_InitSpectator();
+       }
+}
+
+void SetSpectatee(entity this, entity spectatee)
+{
+       entity old_spectatee = this.enemy;
+
+       this.enemy = spectatee;
+
+       // WEAPONTODO
+       // these are required to fix the spectator bug with arc
+       if(old_spectatee)
+       {
+               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+               {
+                       .entity weaponentity = weaponentities[slot];
+                       if(old_spectatee.(weaponentity).arc_beam)
+                               old_spectatee.(weaponentity).arc_beam.SendFlags |= ARC_SF_SETTINGS;
+               }
+       }
+       if(this.enemy)
+       {
+               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+               {
+                       .entity weaponentity = weaponentities[slot];
+                       if(this.enemy.(weaponentity).arc_beam)
+                               this.enemy.(weaponentity).arc_beam.SendFlags |= ARC_SF_SETTINGS;
+               }
+       }
+
+       if (this.enemy)
+               SetSpectatee_status(this, etof(this.enemy));
+
+       // needed to update spectator list
+       if(old_spectatee) { ClientData_Touch(old_spectatee); }
+}
+
+bool Spectate(entity this, entity pl)
+{
+       if(MUTATOR_CALLHOOK(SpectateSet, this, pl))
+               return false;
+       pl = M_ARGV(1, entity);
+
+       SetSpectatee(this, pl);
+       return SpectateSet(this);
+}
+
+bool SpectateNext(entity this)
+{
+       entity ent = find(this.enemy, classname, STR_PLAYER);
+
+       if (MUTATOR_CALLHOOK(SpectateNext, this, ent))
+               ent = M_ARGV(1, entity);
+       else if (!ent)
+               ent = find(ent, classname, STR_PLAYER);
+
+       if(ent) { SetSpectatee(this, ent); }
+
+       return SpectateSet(this);
+}
+
+bool SpectatePrev(entity this)
+{
+       // NOTE: chain order is from the highest to the lower entnum (unlike find)
+       entity ent = findchain(classname, STR_PLAYER);
+       if (!ent) // no player
+               return false;
+
+       entity first = ent;
+       // skip players until current spectated player
+       if(this.enemy)
+       while(ent && ent != this.enemy)
+               ent = ent.chain;
+
+       switch (MUTATOR_CALLHOOK(SpectatePrev, this, ent, first))
+       {
+               case MUT_SPECPREV_FOUND:
+                   ent = M_ARGV(1, entity);
+                   break;
+               case MUT_SPECPREV_RETURN:
+                   return true;
+               case MUT_SPECPREV_CONTINUE:
+               default:
+               {
+                       if(ent.chain)
+                               ent = ent.chain;
+                       else
+                               ent = first;
+                       break;
+               }
+       }
+
+       SetSpectatee(this, ent);
+       return SpectateSet(this);
+}
+
+/*
+=============
+ShowRespawnCountdown()
+
+Update a respawn countdown display.
+=============
+*/
+void ShowRespawnCountdown(entity this)
+{
+       float number;
+       if(!IS_DEAD(this)) // just respawned?
+               return;
+       else
+       {
+               number = ceil(this.respawn_time - time);
+               if(number <= 0)
+                       return;
+               if(number <= this.respawn_countdown)
+               {
+                       this.respawn_countdown = number - 1;
+                       if(ceil(this.respawn_time - (time + 0.5)) == number) // only say it if it is the same number even in 0.5s; to prevent overlapping sounds
+                               { Send_Notification(NOTIF_ONE, this, MSG_ANNCE, Announcer_PickNumber(CNT_RESPAWN, number)); }
+               }
+       }
+}
+
+.float caplayer;
+
+void LeaveSpectatorMode(entity this)
+{
+       if(this.caplayer)
+               return;
+       if(nJoinAllowed(this, this))
+       {
+               if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (this.wasplayer && autocvar_g_changeteam_banned) || this.team_forced > 0)
+               {
+                       TRANSMUTE(Player, this);
+
+                       SetSpectatee(this, NULL);
+
+                       if(autocvar_g_campaign || autocvar_g_balance_teams)
+                               { JoinBestTeam(this, false, true); }
+
+                       if(autocvar_g_campaign)
+                               { campaign_bots_may_start = true; }
+
+                       Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_PREVENT_JOIN);
+
+                       PutClientInServer(this);
+
+                       if(IS_PLAYER(this)) { Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((teamplay && this.team != -1) ? APP_TEAM_ENT(this, INFO_JOIN_PLAY_TEAM) : INFO_JOIN_PLAY), this.netname); }
+               }
+               else
+                       stuffcmd(this, "menu_showteamselect\n");
+       }
+       else
+       {
+               // Player may not join because g_maxplayers is set
+               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_PREVENT);
+       }
+}
+
+/**
+ * Determines whether the player is allowed to join. This depends on cvar
+ * g_maxplayers, if it isn't used this function always return true, otherwise
+ * it checks whether the number of currently playing players exceeds g_maxplayers.
+ * @return int number of free slots for players, 0 if none
+ */
+bool nJoinAllowed(entity this, entity ignore)
+{
+       if(!ignore)
+       // this is called that way when checking if anyone may be able to join (to build qcstatus)
+       // so report 0 free slots if restricted
+       {
+               if(autocvar_g_forced_team_otherwise == "spectate")
+                       return false;
+               if(autocvar_g_forced_team_otherwise == "spectator")
+                       return false;
+       }
+
+       if(this.team_forced < 0)
+               return false; // forced spectators can never join
+
+       // TODO simplify this
+       int totalClients = 0;
+       int currentlyPlaying = 0;
+       FOREACH_CLIENT(true, LAMBDA(
+               if(it != ignore)
+                       ++totalClients;
+               if(IS_REAL_CLIENT(it))
+               if(IS_PLAYER(it) || it.caplayer)
+                       ++currentlyPlaying;
+       ));
+
+       if (!autocvar_g_maxplayers)
+               return maxclients - totalClients;
+
+       if(currentlyPlaying < autocvar_g_maxplayers)
+               return min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying);
+
+       return false;
+}
+
+/**
+ * Checks whether the client is an observer or spectator, if so, he will get kicked after
+ * g_maxplayers_spectator_blocktime seconds
+ */
+void checkSpectatorBlock(entity this)
+{
+       if(IS_SPEC(this) || IS_OBSERVER(this))
+       if(!this.caplayer)
+       if(IS_REAL_CLIENT(this))
+       {
+               if( time > (this.spectatortime + autocvar_g_maxplayers_spectator_blocktime) ) {
+                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_QUIT_KICK_SPECTATING);
+                       dropclient(this);
+               }
+       }
+}
+
+void PrintWelcomeMessage(entity this)
+{
+       if(this.motd_actived_time == 0)
+       {
+               if (autocvar_g_campaign) {
+                       if ((IS_PLAYER(this) && PHYS_INPUT_BUTTON_INFO(this)) || (!IS_PLAYER(this))) {
+                               this.motd_actived_time = time;
+                               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, campaign_message);
+                       }
+               } else {
+                       if (PHYS_INPUT_BUTTON_INFO(this)) {
+                               this.motd_actived_time = time;
+                               Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, getwelcomemessage(this));
+                       }
+               }
+       }
+       else if(this.motd_actived_time > 0) // showing MOTD or campaign message
+       {
+               if (autocvar_g_campaign) {
+                       if (PHYS_INPUT_BUTTON_INFO(this))
+                               this.motd_actived_time = time;
+                       else if ((time - this.motd_actived_time > 2) && IS_PLAYER(this)) { // hide it some seconds after BUTTON_INFO has been released
+                               this.motd_actived_time = 0;
+                               Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_MOTD);
+                       }
+               } else {
+                       if (PHYS_INPUT_BUTTON_INFO(this))
+                               this.motd_actived_time = time;
+                       else if (time - this.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released
+                               this.motd_actived_time = 0;
+                               Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_MOTD);
+                       }
+               }
+       }
+       else //if(this.motd_actived_time < 0) // just connected, motd is active
+       {
+               if(PHYS_INPUT_BUTTON_INFO(this)) // BUTTON_INFO hides initial MOTD
+                       this.motd_actived_time = -2; // wait until BUTTON_INFO gets released
+               else if(this.motd_actived_time == -2 || IS_PLAYER(this) || IS_SPEC(this))
+               {
+                       // instanctly hide MOTD
+                       this.motd_actived_time = 0;
+                       Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_MOTD);
+               }
+       }
+}
+
+void ObserverThink(entity this)
+{
+       if ( this.impulse )
+       {
+               MinigameImpulse(this, this.impulse);
+               this.impulse = 0;
+       }
+       if (this.flags & FL_JUMPRELEASED) {
+               if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) {
+                       this.flags &= ~FL_JUMPRELEASED;
+                       this.flags |= FL_SPAWNING;
+               } else if(PHYS_INPUT_BUTTON_ATCK(this) && !this.version_mismatch) {
+                       this.flags &= ~FL_JUMPRELEASED;
+                       if(SpectateNext(this)) {
+                               TRANSMUTE(Spectator, this);
+                       }
+               } else {
+                       int preferred_movetype = ((!PHYS_INPUT_BUTTON_USE(this) ? this.cvar_cl_clippedspectating : !this.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP);
+                       set_movetype(this, preferred_movetype);
+               }
+       } else {
+               if (!(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this))) {
+                       this.flags |= FL_JUMPRELEASED;
+                       if(this.flags & FL_SPAWNING)
+                       {
+                               this.flags &= ~FL_SPAWNING;
+                               LeaveSpectatorMode(this);
+                               return;
+                       }
+               }
+       }
+}
+
+void SpectatorThink(entity this)
+{
+       if ( this.impulse )
+       {
+               if(MinigameImpulse(this, this.impulse))
+                       this.impulse = 0;
+
+               if (this.impulse == IMP_weapon_drop.impulse)
+               {
+                       STAT(CAMERA_SPECTATOR, this) = (STAT(CAMERA_SPECTATOR, this) + 1) % 3;
+                       this.impulse = 0;
+                       return;
+               }
+       }
+       if (this.flags & FL_JUMPRELEASED) {
+               if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) {
+                       this.flags &= ~FL_JUMPRELEASED;
+                       this.flags |= FL_SPAWNING;
+               } else if(PHYS_INPUT_BUTTON_ATCK(this) || this.impulse == 10 || this.impulse == 15 || this.impulse == 18 || (this.impulse >= 200 && this.impulse <= 209)) {
+                       this.flags &= ~FL_JUMPRELEASED;
+                       if(SpectateNext(this)) {
+                               TRANSMUTE(Spectator, this);
+                       } else {
+                               TRANSMUTE(Observer, this);
+                               PutClientInServer(this);
+                       }
+                       this.impulse = 0;
+               } else if(this.impulse == 12 || this.impulse == 16  || this.impulse == 19 || (this.impulse >= 220 && this.impulse <= 229)) {
+                       this.flags &= ~FL_JUMPRELEASED;
+                       if(SpectatePrev(this)) {
+                               TRANSMUTE(Spectator, this);
+                       } else {
+                               TRANSMUTE(Observer, this);
+                               PutClientInServer(this);
+                       }
+                       this.impulse = 0;
+               } else if (PHYS_INPUT_BUTTON_ATCK2(this)) {
+                       this.flags &= ~FL_JUMPRELEASED;
+                       TRANSMUTE(Observer, this);
+                       PutClientInServer(this);
+               } else {
+                       if(!SpectateUpdate(this))
+                               PutObserverInServer(this);
+               }
+       } else {
+               if (!(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this))) {
+                       this.flags |= FL_JUMPRELEASED;
+                       if(this.flags & FL_SPAWNING)
+                       {
+                               this.flags &= ~FL_SPAWNING;
+                               LeaveSpectatorMode(this);
+                               return;
+                       }
+               }
+               if(!SpectateUpdate(this))
+                       PutObserverInServer(this);
+       }
+
+       this.flags |= FL_CLIENT | FL_NOTARGET;
+}
+
+void vehicles_enter (entity pl, entity veh);
+void PlayerUseKey(entity this)
+{
+       if (!IS_PLAYER(this))
+               return;
+
+       if(this.vehicle)
+       {
+               if(!gameover)
+               {
+                       vehicles_exit(this.vehicle, VHEF_NORMAL);
+                       return;
+               }
+       }
+       else if(autocvar_g_vehicles_enter)
+       {
+               if(!STAT(FROZEN, this))
+               if(!IS_DEAD(this))
+               if(!gameover)
+               {
+                       entity head, closest_target = NULL;
+                       head = WarpZone_FindRadius(this.origin, autocvar_g_vehicles_enter_radius, true);
+
+                       while(head) // find the closest acceptable target to enter
+                       {
+                               if(IS_VEHICLE(head))
+                               if(!IS_DEAD(head))
+                               if(!head.owner || ((head.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(head.owner, this)))
+                               if(head.takedamage != DAMAGE_NO)
+                               {
+                                       if(closest_target)
+                                       {
+                                               if(vlen2(this.origin - head.origin) < vlen2(this.origin - closest_target.origin))
+                                               { closest_target = head; }
+                                       }
+                                       else { closest_target = head; }
+                               }
+
+                               head = head.chain;
+                       }
+
+                       if(closest_target) { vehicles_enter(this, closest_target); return; }
+               }
+       }
+
+       // a use key was pressed; call handlers
+       MUTATOR_CALLHOOK(PlayerUseKey, this);
+}
+
+
+/*
+=============
+PlayerPreThink
+
+Called every frame for each client before the physics are run
+=============
+*/
+.float usekeypressed;
+.float last_vehiclecheck;
+.int items_added;
+void PlayerPreThink (entity this)
+{
+       WarpZone_PlayerPhysics_FixVAngle(this);
+
+    STAT(GAMESTARTTIME, this) = game_starttime;
+       STAT(ROUNDSTARTTIME, this) = round_starttime;
+       STAT(ALLOW_OLDVORTEXBEAM, this) = autocvar_g_allow_oldvortexbeam;
+       STAT(LEADLIMIT, this) = autocvar_leadlimit;
+
+       STAT(WEAPONSINMAP, this) = weaponsInMap;
+
+       if (frametime) {
+               // physics frames: update anticheat stuff
+               anticheat_prethink(this);
+       }
+
+       if (blockSpectators && frametime) {
+               // WORKAROUND: only use dropclient in server frames (frametime set).
+               // Never use it in cl_movement frames (frametime zero).
+               checkSpectatorBlock(this);
+    }
+
+       zoomstate_set = false;
+
+       // Check for nameless players
+       if (isInvisibleString(this.netname)) {
+               this.netname = strzone(sprintf("Player#%d", this.playerid));
+               // stuffcmd(this, strcat("name ", this.netname, "\n")); // maybe?
+       }
+       if (this.netname != this.netname_previous) {
+               if (autocvar_sv_eventlog) {
+                       GameLogEcho(strcat(":name:", ftos(this.playerid), ":", this.netname));
+        }
+               if (this.netname_previous) strunzone(this.netname_previous);
+               this.netname_previous = strzone(this.netname);
+       }
+
+       // version nagging
+       if (this.version_nagtime && this.cvar_g_xonoticversion && time > this.version_nagtime) {
+        this.version_nagtime = 0;
+        if (strstrofs(this.cvar_g_xonoticversion, "git", 0) >= 0 || strstrofs(this.cvar_g_xonoticversion, "autobuild", 0) >= 0) {
+            // git client
+        } else if (strstrofs(autocvar_g_xonoticversion, "git", 0) >= 0 || strstrofs(autocvar_g_xonoticversion, "autobuild", 0) >= 0) {
+            // git server
+            Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_BETA, autocvar_g_xonoticversion, this.cvar_g_xonoticversion);
+        } else {
+            int r = vercmp(this.cvar_g_xonoticversion, autocvar_g_xonoticversion);
+            if (r < 0) { // old client
+                Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_OUTDATED, autocvar_g_xonoticversion, this.cvar_g_xonoticversion);
+            } else if (r > 0) { // old server
+                Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_OLD, autocvar_g_xonoticversion, this.cvar_g_xonoticversion);
+            }
+        }
+    }
+
+       // GOD MODE info
+       if (!(this.flags & FL_GODMODE) && this.max_armorvalue)
+       {
+               Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_GODMODE_OFF, this.max_armorvalue);
+               this.max_armorvalue = 0;
+       }
+
+       if (STAT(FROZEN, this) == 2)
+       {
+               this.revive_progress = bound(0, this.revive_progress + frametime * this.revive_speed, 1);
+               this.health = max(1, this.revive_progress * start_health);
+               this.iceblock.alpha = bound(0.2, 1 - this.revive_progress, 1);
+
+               if (this.revive_progress >= 1)
+                       Unfreeze(this);
+       }
+       else if (STAT(FROZEN, this) == 3)
+       {
+               this.revive_progress = bound(0, this.revive_progress - frametime * this.revive_speed, 1);
+               this.health = max(0, autocvar_g_nades_ice_health + (start_health-autocvar_g_nades_ice_health) * this.revive_progress );
+
+               if (this.health < 1)
+               {
+                       if (this.vehicle)
+                               vehicles_exit(this.vehicle, VHEF_RELEASE);
+                       if(this.event_damage)
+                               this.event_damage(this, this, this.frozen_by, 1, DEATH_NADE_ICE_FREEZE.m_id, this.origin, '0 0 0');
+               }
+               else if (this.revive_progress <= 0)
+                       Unfreeze(this);
+       }
+
+       MUTATOR_CALLHOOK(PlayerPreThink, this);
+
+       if(autocvar_g_vehicles_enter && (time > this.last_vehiclecheck) && !gameover && !this.vehicle)
+       if(IS_PLAYER(this) && !STAT(FROZEN, this) && !IS_DEAD(this))
+       {
+               FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_vehicles_enter_radius, IS_VEHICLE(it),
+               {
+                       if(!IS_DEAD(it) && it.takedamage != DAMAGE_NO)
+                       if((it.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(it.owner, this))
+                       {
+                               Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_GUNNER);
+                       }
+                       else if(!it.owner)
+                       {
+                               if(!it.team || SAME_TEAM(this, it))
+                                       Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER);
+                               else if(autocvar_g_vehicles_steal)
+                                       Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_STEAL);
+                       }
+               });
+
+               this.last_vehiclecheck = time + 1;
+       }
+
+       if(!this.cvar_cl_newusekeysupported) // FIXME remove this - it was a stupid idea to begin with, we can JUST use the button
+       {
+               if(PHYS_INPUT_BUTTON_USE(this) && !this.usekeypressed)
+                       PlayerUseKey(this);
+               this.usekeypressed = PHYS_INPUT_BUTTON_USE(this);
+       }
+
+       if (IS_REAL_CLIENT(this))
+               PrintWelcomeMessage(this);
+
+       if (IS_PLAYER(this)) {
+               CheckRules_Player(this);
+
+               if (intermission_running) {
+                       IntermissionThink(this);
+                       return;
+               }
+
+               if (timeout_status == TIMEOUT_ACTIVE) {
+            // don't allow the player to turn around while game is paused
+                       // FIXME turn this into CSQC stuff
+                       this.v_angle = this.lastV_angle;
+                       this.angles = this.lastV_angle;
+                       this.fixangle = true;
+               }
+
+               if (frametime) player_powerups(this);
+
+               if (IS_DEAD(this)) {
+                       if (this.personal && g_race_qualifying) {
+                               if (time > this.respawn_time) {
+                                       STAT(RESPAWN_TIME, this) = this.respawn_time = time + 1; // only retry once a second
+                                       respawn(this);
+                                       this.impulse = CHIMPULSE_SPEEDRUN.impulse;
+                               }
+                       } else {
+                               if (frametime) player_anim(this);
+                               bool button_pressed = (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));
+
+                               switch(this.deadflag)
+                               {
+                                       case DEAD_DYING:
+                                       {
+                                               if ((this.respawn_flags & RESPAWN_FORCE) && !(this.respawn_time < this.respawn_time_max))
+                                                       this.deadflag = DEAD_RESPAWNING;
+                                               else if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE))
+                                                       this.deadflag = DEAD_DEAD;
+                                               break;
+                                       }
+                                       case DEAD_DEAD:
+                                       {
+                                               if (button_pressed)
+                                                       this.deadflag = DEAD_RESPAWNABLE;
+                                               else if (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE))
+                                                       this.deadflag = DEAD_RESPAWNING;
+                                               break;
+                                       }
+                                       case DEAD_RESPAWNABLE:
+                                       {
+                                               if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE))
+                                                       this.deadflag = DEAD_RESPAWNING;
+                                               break;
+                                       }
+                                       case DEAD_RESPAWNING:
+                                       {
+                                               if (time > this.respawn_time)
+                                               {
+                                                       this.respawn_time = time + 1; // only retry once a second
+                                                       this.respawn_time_max = this.respawn_time;
+                                                       respawn(this);
+                                               }
+                                               break;
+                                       }
+                               }
+
+                               ShowRespawnCountdown(this);
+
+                               if (this.respawn_flags & RESPAWN_SILENT)
+                                       STAT(RESPAWN_TIME, this) = 0;
+                               else if ((this.respawn_flags & RESPAWN_FORCE) && this.respawn_time < this.respawn_time_max)
+                               {
+                                       if (time < this.respawn_time)
+                                               STAT(RESPAWN_TIME, this) = this.respawn_time;
+                                       else if (this.deadflag != DEAD_RESPAWNING)
+                                               STAT(RESPAWN_TIME, this) = -this.respawn_time_max;
+                               }
+                               else
+                                       STAT(RESPAWN_TIME, this) = this.respawn_time;
+                       }
+
+                       // if respawning, invert stat_respawn_time to indicate this, the client translates it
+                       if (this.deadflag == DEAD_RESPAWNING && STAT(RESPAWN_TIME, this) > 0)
+                               STAT(RESPAWN_TIME, this) *= -1;
+
+                       return;
+               }
+
+               this.prevorigin = this.origin;
+
+               bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
+               if (this.hook.state) {
+                       do_crouch = false;
+               } else if (this.waterlevel >= WATERLEVEL_SWIMMING) {
+                       do_crouch = false;
+               } else if (this.vehicle) {
+                       do_crouch = false;
+               } else if (STAT(FROZEN, this)) {
+                       do_crouch = false;
+        }
+
+               if (do_crouch) {
+                       if (!this.crouch) {
+                               this.crouch = true;
+                               this.view_ofs = STAT(PL_CROUCH_VIEW_OFS, this);
+                               setsize(this, STAT(PL_CROUCH_MIN, this), STAT(PL_CROUCH_MAX, this));
+                               // setanim(this, this.anim_duck, false, true, true); // this anim is BROKEN anyway
+                       }
+               } else if (this.crouch) {
+            tracebox(this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this), this.origin, false, this);
+            if (!trace_startsolid) {
+                this.crouch = false;
+                this.view_ofs = STAT(PL_VIEW_OFS, this);
+                setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this));
+            }
+               }
+
+               FixPlayermodel(this);
+
+               // LordHavoc: allow firing on move frames (sub-ticrate), this gives better timing on slow servers
+               //if(frametime)
+               {
+                       this.items &= ~this.items_added;
+
+                       //for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+                       //{
+                               //.entity weaponentity = weaponentities[slot];
+                               //W_WeaponFrame(this, weaponentity);
+                       //}
+                       .entity weaponentity = weaponentities[0]; // TODO
+                       W_WeaponFrame(this, weaponentity);
+
+                       this.items_added = 0;
+                       if (this.items & ITEM_Jetpack.m_itemid && (this.items & ITEM_JetpackRegen.m_itemid || this.ammo_fuel >= 0.01))
+                this.items_added |= IT_FUEL;
+
+                       this.items |= this.items_added;
+               }
+
+               player_regen(this);
+
+               // WEAPONTODO: Add a weapon request for this
+               // rot vortex charge to the charge limit
+               if (WEP_CVAR(vortex, charge_rot_rate) && this.vortex_charge > WEP_CVAR(vortex, charge_limit) && this.vortex_charge_rottime < time)
+                       this.vortex_charge = bound(WEP_CVAR(vortex, charge_limit), this.vortex_charge - WEP_CVAR(vortex, charge_rot_rate) * frametime / W_TICSPERFRAME, 1);
+
+               if (frametime) player_anim(this);
+
+               // secret status
+               secrets_setstatus(this);
+
+               // monsters status
+               monsters_setstatus(this);
+
+               this.dmg_team = max(0, this.dmg_team - autocvar_g_teamdamage_resetspeed * frametime);
+       }
+       else if (gameover) {
+               if (intermission_running) IntermissionThink(this);
+               return;
+       }
+       else if (IS_OBSERVER(this)) {
+               ObserverThink(this);
+       }
+       else if (IS_SPEC(this)) {
+               SpectatorThink(this);
+       }
+
+       // WEAPONTODO: Add weapon request for this
+       if (!zoomstate_set) {
+               SetZoomState(this,
+                       PHYS_INPUT_BUTTON_ZOOM(this) || PHYS_INPUT_BUTTON_ZOOMSCRIPT(this)
+                       || (PHYS_INPUT_BUTTON_ATCK2(this) && PS(this).m_weapon == WEP_VORTEX)
+                       || (PHYS_INPUT_BUTTON_ATCK2(this) && PS(this).m_weapon == WEP_RIFLE && WEP_CVAR(rifle, secondary) == 0)
+               );
+    }
+
+       if (this.teamkill_soundtime && time > this.teamkill_soundtime)
+       {
+               this.teamkill_soundtime = 0;
+
+               entity e = this.teamkill_soundsource;
+               entity oldpusher = e.pusher;
+               e.pusher = this;
+               PlayerSound(e, playersound_teamshoot, CH_VOICE, VOL_BASEVOICE, VOICETYPE_LASTATTACKER_ONLY);
+               e.pusher = oldpusher;
+       }
+
+       if (this.taunt_soundtime && time > this.taunt_soundtime) {
+               this.taunt_soundtime = 0;
+               PlayerSound(this, playersound_taunt, CH_VOICE, VOL_BASEVOICE, VOICETYPE_AUTOTAUNT);
+       }
+
+       target_voicescript_next(this);
+
+       // WEAPONTODO: Move into weaponsystem somehow
+       // if a player goes unarmed after holding a loaded weapon, empty his clip size and remove the crosshair ammo ring
+       if (PS(this).m_weapon == WEP_Null)
+               this.clip_load = this.clip_size = 0;
+}
+
+void DrownPlayer(entity this)
+{
+       if(IS_DEAD(this))
+               return;
+
+       if (this.waterlevel != WATERLEVEL_SUBMERGED || this.vehicle)
+       {
+               if(this.air_finished < time)
+                       PlayerSound(this, playersound_gasp, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND);
+               this.air_finished = time + autocvar_g_balance_contents_drowndelay;
+               this.dmg = 2;
+       }
+       else if (this.air_finished < time)
+       {       // drown!
+               if (this.pain_finished < time)
+               {
+                       Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_drowning * autocvar_g_balance_contents_damagerate, DEATH_DROWN.m_id, this.origin, '0 0 0');
+                       this.pain_finished = time + 0.5;
+               }
+       }
+}
+
+.bool move_qcphysics;
+
+void Player_Physics(entity this)
+{
+       set_movetype(this, this.move_movetype);
+
+       if(!this.move_qcphysics)
+               return;
+
+       if(!frametime && !this.pm_frametime)
+               return;
+
+       Movetype_Physics_NoMatchTicrate(this, this.pm_frametime, true);
+
+       this.pm_frametime = 0;
+}
+
+/*
+=============
+PlayerPostThink
+
+Called every frame for each client after the physics are run
+=============
+*/
+.float idlekick_lasttimeleft;
+void PlayerPostThink (entity this)
+{
+       Player_Physics(this);
+
+       if (sv_maxidle > 0)
+       if (frametime) // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
+       if (IS_REAL_CLIENT(this))
+       if (IS_PLAYER(this) || sv_maxidle_spectatorsareidle)
+       {
+               int totalClients = 0;
+               if(sv_maxidle_slots > 0)
+               {
+                       FOREACH_CLIENT(IS_REAL_CLIENT(it) || sv_maxidle_slots_countbots,
+                       {
+                               ++totalClients;
+                       });
+               }
+
+               if (sv_maxidle_slots > 0 && (maxclients - totalClients) > sv_maxidle_slots)
+               { /* do nothing */ }
+               else if (time - this.parm_idlesince < 1) // instead of (time == this.parm_idlesince) to support sv_maxidle <= 10
+               {
+                       if (this.idlekick_lasttimeleft)
+                       {
+                               this.idlekick_lasttimeleft = 0;
+                               Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_IDLING);
+                       }
+               }
+               else
+               {
+                       float timeleft = ceil(sv_maxidle - (time - this.parm_idlesince));
+                       if (timeleft == min(10, sv_maxidle - 1)) { // - 1 to support sv_maxidle <= 10
+                               if (!this.idlekick_lasttimeleft)
+                                       Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_DISCONNECT_IDLING, timeleft);
+                       }
+                       if (timeleft <= 0) {
+                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_KICK_IDLING, this.netname);
+                               dropclient(this);
+                               return;
+                       }
+                       else if (timeleft <= 10) {
+                               if (timeleft != this.idlekick_lasttimeleft) {
+                                   Send_Notification(NOTIF_ONE, this, MSG_ANNCE, Announcer_PickNumber(CNT_IDLE, timeleft));
+                }
+                               this.idlekick_lasttimeleft = timeleft;
+                       }
+               }
+       }
+
+       CheatFrame(this);
+
+       //CheckPlayerJump();
+
+       if (IS_PLAYER(this)) {
+               DrownPlayer(this);
+               CheckRules_Player(this);
+               UpdateChatBubble(this);
+               if (this.impulse) ImpulseCommands(this);
+               if (intermission_running) return; // intermission or finale
+               GetPressedKeys(this);
+       }
+
+       if (this.waypointsprite_attachedforcarrier) {
+           vector v = healtharmor_maxdamage(this.health, this.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id);
+               WaypointSprite_UpdateHealth(this.waypointsprite_attachedforcarrier, '1 0 0' * v);
+    }
+
+       playerdemo_write(this);
+
+       CSQCMODEL_AUTOUPDATE(this);
+}
diff --git a/qcsrc/server/client.qh b/qcsrc/server/client.qh
new file mode 100644 (file)
index 0000000..c2317af
--- /dev/null
@@ -0,0 +1,115 @@
+#pragma once
+
+void ClientState_attach(entity this);
+
+IntrusiveList g_players;
+STATIC_INIT(g_players) { g_players = IL_NEW(); }
+
+CLASS(Client, Object)
+    /** Client name */
+    ATTRIB(Client, netname, string, this.netname);
+    ATTRIB(Client, colormap, int, this.colormap);
+    ATTRIB(Client, team, int, this.team);
+    ATTRIB(Client, clientcolors, int, this.clientcolors);
+    /** Client IP */
+    ATTRIB(Client, netaddress, string, this.netaddress);
+    ATTRIB(Client, playermodel, string, this.playermodel);
+    ATTRIB(Client, playerskin, int, this.playerskin);
+
+    /** fingerprint of CA key the player used to authenticate */
+    ATTRIB(Client, crypto_keyfp, string, this.crypto_keyfp);
+    /** fingerprint of CA key the server used to authenticate to the player */
+    ATTRIB(Client, crypto_mykeyfp, string, this.crypto_mykeyfp);
+    /** fingerprint of ID used by the player entity, or string_null if not identified */
+    ATTRIB(Client, crypto_idfp, string, this.crypto_idfp);
+    /** set if the player's ID has been signed */
+    ATTRIB(Client, crypto_idfp_signed, bool, this.crypto_idfp_signed);
+    /** the string "AES128" if encrypting, and string_null if plaintext */
+    ATTRIB(Client, crypto_encryptmethod, string, this.crypto_encryptmethod);
+    /** the string "HMAC-SHA256" if signing, and string_null if plaintext */
+    ATTRIB(Client, crypto_signmethod, string, this.crypto_signmethod);
+
+    // custom
+
+    ATTRIB(Client, playerid, int, this.playerid);
+
+    METHOD(Client, m_unwind, bool(Client this));
+
+    STATIC_METHOD(Client, Add, void(Client this, int _team));
+    STATIC_METHOD(Client, Remove, void(Client this));
+
+    INIT(Client) {
+        if (this.m_unwind(this)) return this;
+        make_impure(this);
+        this.classname = "player_joining";
+        static int playerid_last;
+        this.playerid = ++playerid_last;
+        ClientState_attach(this);
+    }
+    DESTRUCTOR(Client) {
+        Client_Remove(this);
+    }
+    CONSTRUCTOR(Client, string name) {
+        CONSTRUCT(Client);
+        this.netname = name;
+        this.netaddress = "local";
+        this.playermodel = "models/player/megaerebus.iqm";
+    }
+ENDCLASS(Client)
+
+CLASS(Observer, Client)
+    INIT(Observer) {
+        this.classname = STR_OBSERVER;
+    }
+    DESTRUCTOR(Observer) { }
+ENDCLASS(Observer)
+
+CLASS(Spectator, Client)
+    INIT(Spectator) {
+        this.classname = STR_SPECTATOR;
+    }
+    DESTRUCTOR(Spectator) { }
+ENDCLASS(Spectator)
+
+CLASS(Player, Client)
+    INIT(Player) {
+        this.classname = STR_PLAYER;
+        IL_PUSH(g_players, this);
+    }
+    DESTRUCTOR(Player) {
+        IL_REMOVE(g_players, this);
+    }
+ENDCLASS(Player)
+
+METHOD(Client, m_unwind, bool(Client this))
+{
+    TC(Client, this);
+    #define UNWIND(class) MACRO_BEGIN if (this.instanceOf##class) { METHOD_REFERENCE(class, dtorimpl)(this); } MACRO_END
+    switch (this.classname) {
+        case "Observer":
+            UNWIND(Spectator);
+            UNWIND(Player);
+            return true;
+        case "Spectator":
+            UNWIND(Observer);
+            UNWIND(Player);
+            return true;
+        case "Player":
+            UNWIND(Observer);
+            UNWIND(Spectator);
+            return true;
+    }
+    #undef UNWIND
+    return false;
+}
+
+float c1, c2, c3, c4;
+
+void play_countdown(entity this, float finished, Sound samp);
+
+float CalcRotRegen(float current, float regenstable, float regenfactor, float regenlinear, float regenframetime, float rotstable, float rotfactor, float rotlinear, float rotframetime, float limit);
+
+bool Spectate(entity this, entity pl);
+
+#define SPECTATE_COPY() [[accumulate]] void SpectateCopy(entity this, entity spectatee)
+#define SPECTATE_COPYFIELD(fld) SPECTATE_COPY() { this.(fld) = spectatee.(fld); }
index fa15432311d98b7a247ca547451b3fbdd6310131..2cabd69c7f8f35fb58e029bb4bb629c85dbf3bbd 100644 (file)
@@ -1,5 +1,4 @@
 // generated file; do not modify
-#include <server/command/all.qc>
 #include <server/command/banning.qc>
 #include <server/command/cmd.qc>
 #ifdef SVQC
@@ -8,4 +7,5 @@
 #include <server/command/common.qc>
 #include <server/command/getreplies.qc>
 #include <server/command/radarmap.qc>
+#include <server/command/reg.qc>
 #include <server/command/vote.qc>
index 60e34ffe521214af8f4e232cd59c93b0a4e406fc..6a3b175a4bad845e0692e2f9446d6b8b21d89bfb 100644 (file)
@@ -1,8 +1,11 @@
 // generated file; do not modify
-#include <server/command/all.qh>
 #include <server/command/banning.qh>
 #include <server/command/cmd.qh>
+#ifdef SVQC
+    #include <server/command/sv_cmd.qh>
+#endif
 #include <server/command/common.qh>
 #include <server/command/getreplies.qh>
 #include <server/command/radarmap.qh>
+#include <server/command/reg.qh>
 #include <server/command/vote.qh>
diff --git a/qcsrc/server/command/all.qc b/qcsrc/server/command/all.qc
deleted file mode 100644 (file)
index bc15eeb..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "all.qh"
-#include <common/command/all.qc>
diff --git a/qcsrc/server/command/all.qh b/qcsrc/server/command/all.qh
deleted file mode 100644 (file)
index cde5ef3..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#pragma once
-
-#include <common/command/command.qh>
-REGISTRY(SERVER_COMMANDS, BITS(7))
-#define SERVER_COMMANDS_from(i) _SERVER_COMMANDS_from(i, NULL)
-REGISTER_REGISTRY(SERVER_COMMANDS)
-REGISTRY_SORT(SERVER_COMMANDS)
-
-#define SERVER_COMMAND(id, description) \
-       CLASS(servercommand_##id, Command) \
-               ATTRIB(servercommand_##id, m_name, string, #id); \
-       ATTRIB(servercommand_##id, m_description, string, description); \
-       ENDCLASS(servercommand_##id) \
-    REGISTER(SERVER_COMMANDS, CMD_SV, id, m_id, NEW(servercommand_##id)); \
-       METHOD(servercommand_##id, m_invokecmd, void(servercommand_##id this, int request, entity caller, int arguments, string command))
-
-STATIC_INIT(SERVER_COMMANDS_aliases) {
-       FOREACH(SERVER_COMMANDS, true, LAMBDA(localcmd(sprintf("alias %1$s \"%2$s %1$s ${* ?}\"\n", it.m_name, "qc_cmd_sv"))));
-}
-
-#include "sv_cmd.qh"
-
-#include "banning.qh"
-#include "cmd.qh"
-#include "common.qh"
-#include "getreplies.qh"
-#include "radarmap.qh"
-#include "vote.qh"
index d6968c262de869826bd4f82db3247e514bbfdd2b..8a35bec2925c2f89658dfe7145308e56dabb0c2a 100644 (file)
@@ -1,10 +1,10 @@
 #include "banning.qh"
-#include <common/command/command.qh>
+#include <common/command/_mod.qh>
 #include "banning.qh"
 
 #include "common.qh"
 
-#include "../cl_player.qh"
+#include "../player.qh"
 #include "../ipban.qh"
 
 #include <common/util.qh>
index 13c883f36b8619c79947b229a7322357d0a3d0e0..ce6592408cb4a3fa50af5cf90d0a19eee5271f4a 100644 (file)
@@ -1,18 +1,18 @@
 #include "cmd.qh"
-#include <common/command/command.qh>
+#include <common/command/_mod.qh>
 
 #include "common.qh"
 #include "vote.qh"
 
 #include "../campaign.qh"
 #include "../cheats.qh"
-#include "../cl_player.qh"
+#include "../player.qh"
 #include "../ipban.qh"
 #include "../mapvoting.qh"
 #include "../scores.qh"
 #include "../teamplay.qh"
 
-#include "../mutators/all.qh"
+#include "../mutators/_mod.qh"
 
 #ifdef SVQC
        #include <common/vehicles/all.qh>
@@ -30,8 +30,8 @@
 
 #include <common/minigames/sv_minigames.qh>
 
-#include <common/monsters/all.qc>
-#include <common/monsters/spawn.qh>
+#include <common/monsters/_mod.qh>
+#include <common/monsters/sv_spawn.qh>
 #include <common/monsters/sv_monsters.qh>
 
 #include <lib/warpzone/common.qh>
index d980a0f4cf2d42334e070e5d0d12e6b7bc11b8e9..35418a02f07d420a9e0805f341a73cbaa6632ca5 100644 (file)
@@ -1,10 +1,10 @@
 #include "common.qh"
-#include <common/command/command.qh>
+#include <common/command/_mod.qh>
 #include "common.qh"
 
 #include "../scores.qh"
 
-#include <common/monsters/all.qh>
+#include <common/monsters/_mod.qh>
 #include <common/notifications/all.qh>
 #include <lib/warpzone/common.qh>
 
index 63b1c708f21f1bdea6a7fe441988bc2dd57e97bd..978a92b14f0c1fd4f6d5224f4a3610cf9caf67d9 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <common/command/command.qh>
+#include <common/command/_mod.qh>
 REGISTRY(COMMON_COMMANDS, BITS(7))
 #define COMMON_COMMANDS_from(i) _COMMON_COMMANDS_from(i, NULL)
 REGISTER_REGISTRY(COMMON_COMMANDS)
@@ -19,10 +19,9 @@ STATIC_INIT(COMMON_COMMANDS_aliases) {
 }
 
 #include "vote.qh"
-#include <common/monsters/spawn.qh>
+#include <common/monsters/sv_spawn.qh>
 
-#include <common/command/generic.qh>
-#include <common/command/command.qh>
+#include <common/command/_mod.qh>
 
 // ============================================================
 //  Shared declarations for server commands, written by Samual
index 93ce85a61a89b36b4c849bf2167ae4cebad3cd6f..9380fc4cde280f0cd9fda57a24cd6bddbd41da56 100644 (file)
@@ -1,5 +1,5 @@
 #include "getreplies.qh"
-#include <common/command/command.qh>
+#include <common/command/_mod.qh>
 #include "getreplies.qh"
 
 #include "../race.qh"
@@ -8,7 +8,7 @@
 #include <common/mapinfo.qh>
 #include <common/util.qh>
 
-#include <common/monsters/all.qh>
+#include <common/monsters/_mod.qh>
 
 // =========================================================
 //  Reply messages for common commands, re-worked by Samual
index 71f5e270b1e80cef9e8aa59d2c0285aa3aa84846..a5e4a7547a51289d1d670dca53676910de761daa 100644 (file)
@@ -1,5 +1,5 @@
 #include "radarmap.qh"
-#include <common/command/command.qh>
+#include <common/command/_mod.qh>
 #include "radarmap.qh"
 
 #include "../g_world.qh"
@@ -26,7 +26,7 @@ float FullTraceFraction(vector a, vector mi, vector ma, vector b)
        float n, m;
        n = m = 0;
 
-       while (vlen(c - b) > 1)
+       while (vdist(c - b, >, 1))
        {
                ++m;
 
diff --git a/qcsrc/server/command/reg.qc b/qcsrc/server/command/reg.qc
new file mode 100644 (file)
index 0000000..c0af5b5
--- /dev/null
@@ -0,0 +1 @@
+#include "reg.qh"
diff --git a/qcsrc/server/command/reg.qh b/qcsrc/server/command/reg.qh
new file mode 100644 (file)
index 0000000..b135c04
--- /dev/null
@@ -0,0 +1,18 @@
+#pragma once
+
+REGISTRY(SERVER_COMMANDS, BITS(7))
+#define SERVER_COMMANDS_from(i) _SERVER_COMMANDS_from(i, NULL)
+REGISTER_REGISTRY(SERVER_COMMANDS)
+REGISTRY_SORT(SERVER_COMMANDS)
+
+#define SERVER_COMMAND(id, description) \
+       CLASS(servercommand_##id, Command) \
+               ATTRIB(servercommand_##id, m_name, string, #id); \
+       ATTRIB(servercommand_##id, m_description, string, description); \
+       ENDCLASS(servercommand_##id) \
+    REGISTER(SERVER_COMMANDS, CMD_SV, id, m_id, NEW(servercommand_##id)); \
+       METHOD(servercommand_##id, m_invokecmd, void(servercommand_##id this, int request, entity caller, int arguments, string command))
+
+STATIC_INIT(SERVER_COMMANDS_aliases) {
+       FOREACH(SERVER_COMMANDS, true, LAMBDA(localcmd(sprintf("alias %1$s \"%2$s %1$s ${* ?}\"\n", it.m_name, "qc_cmd_sv"))));
+}
index bb59566d2a7e6da9bdf9231589aba6299f4e8f6f..a329ac9965efe463b052d92a24ac64b6ccddea1a 100644 (file)
@@ -1,5 +1,5 @@
 #include "sv_cmd.qh"
-#include "all.qh"
+#include "_mod.qh"
 
 #include "banning.qh"
 #include "cmd.qh"
@@ -9,8 +9,8 @@
 
 #include "../anticheat.qh"
 #include "../campaign.qh"
-#include "../cl_client.qh"
-#include "../cl_player.qh"
+#include "../client.qh"
+#include "../player.qh"
 #include "../g_world.qh"
 #include "../ipban.qh"
 #include "../playerdemo.qh"
@@ -18,7 +18,7 @@
 
 #include "../bot/api.qh"
 
-#include "../mutators/all.qh"
+#include "../mutators/_mod.qh"
 
 #include <common/constants.qh>
 #include <common/mapinfo.qh>
index 72bedd982ca79797397b9d811b8362752a9b2b95..361f1284436f9f85520c4902d80dfae92ea58203 100644 (file)
@@ -1,5 +1,5 @@
 #include "vote.qh"
-#include <common/command/command.qh>
+#include <common/command/_mod.qh>
 #include "vote.qh"
 
 #include "common.qh"
@@ -10,7 +10,7 @@
 #include "../round_handler.qh"
 #include "../scores.qh"
 
-#include "../mutators/all.qh"
+#include "../mutators/_mod.qh"
 
 #include <common/constants.qh>
 #include <common/mapinfo.qh>
index d2b4b148efffff48763f65ffe292132d05887ce6..b034968901e741e40d348952fdf7ef40ab16f9d9 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 float warmup_limit;
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 #include <common/stats.qh>
 
 #define INDEPENDENT_ATTACK_FINISHED 1
@@ -12,20 +12,6 @@ float g_footsteps, g_grappling_hook, g_instagib;
 float g_warmup_allguns;
 float g_warmup_allow_timeout;
 float warmup_stage;
-PROPERTY(float, g_pickup_respawntime_weapon)
-PROPERTY(float, g_pickup_respawntime_superweapon)
-PROPERTY(float, g_pickup_respawntime_ammo)
-PROPERTY(float, g_pickup_respawntime_short)
-PROPERTY(float, g_pickup_respawntime_medium)
-PROPERTY(float, g_pickup_respawntime_long)
-PROPERTY(float, g_pickup_respawntime_powerup)
-PROPERTY(float, g_pickup_respawntimejitter_weapon)
-PROPERTY(float, g_pickup_respawntimejitter_superweapon)
-PROPERTY(float, g_pickup_respawntimejitter_ammo)
-PROPERTY(float, g_pickup_respawntimejitter_short)
-PROPERTY(float, g_pickup_respawntimejitter_medium)
-PROPERTY(float, g_pickup_respawntimejitter_long)
-PROPERTY(float, g_pickup_respawntimejitter_powerup)
 float g_jetpack;
 
 float sv_clones;
@@ -440,7 +426,6 @@ const int MIF_GUIDED_CONFUSABLE = MIF_GUIDED_HEAT | MIF_GUIDED_AI;
 
 .string cvar_cl_physics;
 
-.bool init_for_player_needed;
 .void(entity this, entity player) init_for_player;
 
 IntrusiveList g_monsters;
@@ -460,3 +445,30 @@ STATIC_INIT(g_mines) { g_mines = IL_NEW(); }
 
 IntrusiveList g_projectiles;
 STATIC_INIT(g_projectiles) { g_projectiles = IL_NEW(); }
+
+IntrusiveList g_items;
+STATIC_INIT(g_items) { g_items = IL_NEW(); }
+
+IntrusiveList g_initforplayer;
+STATIC_INIT(g_initforplayer) { g_initforplayer = IL_NEW(); }
+
+IntrusiveList g_clones;
+STATIC_INIT(g_clones) { g_clones = IL_NEW(); }
+
+IntrusiveList g_assault_destructibles;
+STATIC_INIT(g_assault_destructibles) { g_assault_destructibles = IL_NEW(); }
+
+IntrusiveList g_assault_objectivedecreasers;
+STATIC_INIT(g_assault_objectivedecreasers) { g_assault_objectivedecreasers = IL_NEW(); }
+
+IntrusiveList g_assault_objectives;
+STATIC_INIT(g_assault_objectives) { g_assault_objectives = IL_NEW(); }
+
+IntrusiveList g_spawnpoints;
+STATIC_INIT(g_spawnpoints) { g_spawnpoints = IL_NEW(); }
+
+IntrusiveList g_bot_targets;
+STATIC_INIT(g_bot_targets) { g_bot_targets = IL_NEW(); }
+
+IntrusiveList g_bot_dodge;
+STATIC_INIT(g_bot_dodge) { g_bot_dodge = IL_NEW(); }
index d7e9b07c05279a5c26a7f67655d9039ca4339c1a..3e448363655f6ce712a84efb3af74f3202a68db1 100644 (file)
@@ -2,14 +2,14 @@
 
 #include "bot/api.qh"
 #include "g_hook.qh"
-#include "mutators/all.qh"
+#include "mutators/_mod.qh"
 #include "scores.qh"
 #include "spawnpoints.qh"
 #include "../common/state.qh"
 #include "../common/physics/player.qh"
 #include "../common/t_items.qh"
 #include "../common/vehicles/all.qh"
-#include "../common/items/all.qc"
+#include "../common/items/_mod.qh"
 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
 #include "weapons/accuracy.qh"
 #include "weapons/csqcprojectile.qh"
@@ -21,7 +21,7 @@
 #include "../common/playerstats.qh"
 #include "../common/teams.qh"
 #include "../common/util.qh"
-#include "../common/weapons/all.qh"
+#include <common/weapons/_all.qh>
 #include "../lib/csqcmodel/sv_model.qh"
 #include "../lib/warpzone/common.qh"
 
@@ -111,6 +111,8 @@ void GiveFrags (entity attacker, entity targ, float f, int deathtype)
                UpdateFrags(attacker, f);
 }
 
+.entity kh_next;
+
 string AppendItemcodes(string s, entity player)
 {
        int w = PS(player).m_weapon.m_id;
@@ -524,6 +526,8 @@ void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypo
        targ.revive_progress = ((frozen_type == 3) ? 1 : 0);
        targ.health = ((frozen_type == 3) ? targ_maxhealth : 1);
        targ.revive_speed = freeze_time;
+       if(targ.bot_attack)
+               IL_REMOVE(g_bot_targets, targ);
        targ.bot_attack = false;
 
        entity ice = new(ice);
@@ -561,6 +565,8 @@ void Unfreeze (entity targ)
        STAT(FROZEN, targ) = 0;
        targ.revive_progress = 0;
        targ.revival_time = time;
+       if(!targ.bot_attack)
+               IL_PUSH(g_bot_targets, targ);
        targ.bot_attack = true;
 
        WaypointSprite_Kill(targ.waypointsprite_attached);
@@ -788,7 +794,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
                        else
                                victim = targ;
 
-                       if(IS_PLAYER(victim) || (IS_TURRET(victim) && victim.active == ACTIVE_ACTIVE) || IS_MONSTER(victim) || MUTATOR_CALLHOOK(PlayHitsound, victim))
+                       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))
                                {
@@ -833,7 +839,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
 
        // apply push
        if (targ.damageforcescale)
-       if (vlen(force))
+       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);
@@ -857,7 +863,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
                UpdateCSQCProjectile(targ);
        }
        // apply damage
-       if (damage != 0 || (targ.damageforcescale && vlen(force)))
+       if (damage != 0 || (targ.damageforcescale && force))
        if (targ.event_damage)
                targ.event_damage (targ, inflictor, attacker, damage, deathtype, hitloc, force);
 
@@ -1032,7 +1038,7 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in
                                        //      print(" finaldmg ", ftos(finaldmg), " force ", vtos(force));
                                        //      print(" (", ftos(a), ")\n");
                                        //}
-                                       if(finaldmg || vlen(force))
+                                       if(finaldmg || force)
                                        {
                                                if(targ.iscreature)
                                                {
index f11c82c84d2bd1c0019fa350322687ba60997eb4..019c8fc9a8efc92bc5d280f2352d796acd99f574 100644 (file)
@@ -7,7 +7,7 @@
     #include <common/constants.qh>
     #include <common/teams.qh>
     #include <common/util.qh>
-    #include <common/weapons/all.qh>
+    #include <common/weapons/_all.qh>
     #include "weapons/accuracy.qh"
     #include "weapons/csqcprojectile.qh"
     #include "weapons/selection.qh"
@@ -17,7 +17,7 @@
     #include "defs.qh"
     #include <common/notifications/all.qh>
     #include <common/deathtypes/all.qh>
-    #include "mutators/all.qh"
+    #include "mutators/_mod.qh"
     #include <common/turrets/sv_turrets.qh>
     #include <common/vehicles/all.qh>
     #include <lib/csqcmodel/sv_model.qh>
index 1b2662d6e4ede1927712d46266b2afc2f9533771..90266189b83c1adf5f4ea6f7db111c9780e3c24c 100644 (file)
@@ -5,7 +5,7 @@
 #include "weapons/weaponsystem.qh"
 #include "weapons/selection.qh"
 #include "weapons/tracing.qh"
-#include "cl_player.qh"
+#include "player.qh"
 #include "command/common.qh"
 #include "round_handler.qh"
 #include "../common/state.qh"
@@ -13,7 +13,7 @@
 #include "../common/vehicles/all.qh"
 #include "../common/constants.qh"
 #include "../common/util.qh"
-#include "../common/weapons/all.qh"
+#include <common/weapons/_all.qh>
 #include "../lib/warpzone/common.qh"
 #include "../lib/warpzone/server.qh"
 
@@ -371,6 +371,7 @@ void FireGrapplingHook(entity actor)
        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);
index 30cf5517f7ca5f2c3dc095695ace5d4cce3e632f..e3bc706979607a7aa99c1e7a6203027cd67dd417 100644 (file)
@@ -5,7 +5,7 @@
 #include "bot/api.qh"
 #include "campaign.qh"
 #include "cheats.qh"
-#include "cl_client.qh"
+#include "client.qh"
 #include "command/common.qh"
 #include "command/getreplies.qh"
 #include "command/sv_cmd.qh"
@@ -13,7 +13,7 @@
 #include "g_hook.qh"
 #include "ipban.qh"
 #include "mapvoting.qh"
-#include "mutators/all.qh"
+#include "mutators/_mod.qh"
 #include "race.qh"
 #include "scores.qh"
 #include "teamplay.qh"
@@ -21,7 +21,7 @@
 #include "../common/constants.qh"
 #include "../common/deathtypes/all.qh"
 #include "../common/mapinfo.qh"
-#include "../common/monsters/all.qh"
+#include "../common/monsters/_mod.qh"
 #include "../common/monsters/sv_monsters.qh"
 #include "../common/vehicles/all.qh"
 #include "../common/notifications/all.qh"
@@ -32,8 +32,8 @@
 #include "../common/triggers/trigger/secret.qh"
 #include "../common/triggers/target/music.qh"
 #include "../common/util.qh"
-#include "../common/items/all.qh"
-#include "../common/weapons/all.qh"
+#include "../common/items/_mod.qh"
+#include <common/weapons/_all.qh>
 #include "../common/state.qh"
 
 const float LATENCY_THINKRATE = 10;
@@ -555,6 +555,8 @@ spawnfunc(__init_dedicated_server)
        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);
 }
@@ -1332,32 +1334,32 @@ entity FindIntermission()
        local   float cyc;
 
 // look for info_intermission first
-       spot = find (NULL, classname, "info_intermission");
+       spot = find(NULL, classname, "info_intermission");
        if (spot)
        {       // pick a random one
                cyc = random() * 4;
                while (cyc > 1)
                {
-                       spot = find (spot, classname, "info_intermission");
+                       spot = find(spot, classname, "info_intermission");
                        if (!spot)
-                               spot = find (spot, classname, "info_intermission");
+                               spot = find(spot, classname, "info_intermission");
                        cyc = cyc - 1;
                }
                return spot;
        }
 
 // then look for the start position
-       spot = find (NULL, classname, "info_player_start");
+       spot = find(NULL, classname, "info_player_start");
        if (spot)
                return spot;
 
 // testinfo_player_start is only found in regioned levels
-       spot = find (NULL, classname, "testplayerstart");
+       spot = find(NULL, classname, "testplayerstart");
        if (spot)
                return spot;
 
 // then look for the start position
-       spot = find (NULL, classname, "info_player_deathmatch");
+       spot = find(NULL, classname, "info_player_deathmatch");
        if (spot)
                return spot;
 
@@ -1768,7 +1770,8 @@ float WinningCondition_RanOutOfSpawns()
                }
        ));
 
-       FOREACH_ENTITY_CLASS("info_player_deathmatch", true, LAMBDA(
+       IL_EACH(g_spawnpoints, true,
+       {
                switch(it.team)
                {
                        case NUM_TEAM_1: team1_score = 1; break;
@@ -1776,7 +1779,7 @@ float WinningCondition_RanOutOfSpawns()
                        case NUM_TEAM_3: team3_score = 1; break;
                        case NUM_TEAM_4: team4_score = 1; break;
                }
-       ));
+       });
 
        ClearWinners();
        if(team1_score + team2_score + team3_score + team4_score == 0)
@@ -2020,16 +2023,7 @@ void Physics_Frame()
                if(IS_CLIENT(it) || it.classname == "" || it.move_movetype == MOVETYPE_PUSH || it.move_movetype == MOVETYPE_FAKEPUSH || it.move_movetype == MOVETYPE_PHYSICS)
                        continue;
 
-               int mt = it.move_movetype;
-
-               if(mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH || mt == MOVETYPE_PHYSICS)
-               {
-                       it.move_qcphysics = false;
-                       set_movetype(it, mt);
-                       continue;
-               }
-
-               set_movetype(it, ((it.move_qcphysics) ? MOVETYPE_NONE : it.move_movetype));
+               set_movetype(it, it.move_movetype);
 
                if(it.move_movetype == MOVETYPE_NONE)
                        continue;
diff --git a/qcsrc/server/impulse.qc b/qcsrc/server/impulse.qc
new file mode 100644 (file)
index 0000000..8a10a6d
--- /dev/null
@@ -0,0 +1,606 @@
+#include "impulse.qh"
+#include "round_handler.qh"
+
+#include "bot/api.qh"
+
+#include "weapons/throwing.qh"
+#include "command/common.qh"
+#include "cheats.qh"
+#include "weapons/selection.qh"
+#include "weapons/tracing.qh"
+#include "weapons/weaponsystem.qh"
+
+#include <common/state.qh>
+
+#include "../common/minigames/sv_minigames.qh"
+
+#include <common/weapons/_all.qh>
+#include "../common/vehicles/sv_vehicles.qh"
+
+#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
+
+.entity vehicle;
+
+#define IMPULSE(id) _IMPULSE(IMP_##id)
+#define _IMPULSE(id) \
+       void id##_handle(entity this); \
+       STATIC_INIT_LATE(id) \
+       { \
+               id.impulse_handle = id##_handle; \
+       } \
+       void id##_handle(entity this)
+
+/**
+ * Impulse map:
+ *
+ * 0 reserved (no input)
+ *
+ * 99: loaded
+ *
+ * 140: moving clone
+ * 141: ctf speedrun
+ * 142: fixed clone
+ * 143: emergency teleport
+ * 148: unfairly eliminate
+ *
+ * TODO:
+ * 200 to 209: prev weapon shortcuts
+ * 210 to 219: best weapon shortcuts
+ * 220 to 229: next weapon shortcuts
+ * 230 to 253: individual weapons (up to 24)
+ */
+
+// weapon switching impulses
+
+#define X(slot) \
+       IMPULSE(weapon_group_##slot) \
+       { \
+               if (IS_DEAD(this)) \
+               { \
+                       this.impulse = IMP_weapon_group_##slot.impulse; \
+                       return; \
+               } \
+               W_NextWeaponOnImpulse(this, slot); \
+       }
+X(1)
+X(2)
+X(3)
+X(4)
+X(5)
+X(6)
+X(7)
+X(8)
+X(9)
+X(0)
+#undef X
+
+// custom order weapon cycling
+
+#define X(slot, dir) \
+       IMPULSE(weapon_priority_##slot##_##dir) \
+       { \
+               if (this.vehicle) return; \
+               if (IS_DEAD(this)) \
+               { \
+                       this.impulse = IMP_weapon_priority_##slot##_##dir.impulse; \
+                       return; \
+               } \
+               noref int prev = -1; \
+               noref int best =  0; \
+               noref int next = +1; \
+               W_CycleWeapon(this, this.cvar_cl_weaponpriorities[slot], dir); \
+       }
+X(0, prev)
+X(1, prev)
+X(2, prev)
+X(3, prev)
+X(4, prev)
+X(5, prev)
+X(6, prev)
+X(7, prev)
+X(8, prev)
+X(9, prev)
+
+X(0, best)
+X(1, best)
+X(2, best)
+X(3, best)
+X(4, best)
+X(5, best)
+X(6, best)
+X(7, best)
+X(8, best)
+X(9, best)
+
+X(0, next)
+X(1, next)
+X(2, next)
+X(3, next)
+X(4, next)
+X(5, next)
+X(6, next)
+X(7, next)
+X(8, next)
+X(9, next)
+#undef X
+
+// direct weapons
+
+#define X(i) \
+       IMPULSE(weapon_byid_##i) \
+       { \
+               if (this.vehicle) return; \
+               if (IS_DEAD(this)) \
+               { \
+                       this.impulse = IMP_weapon_byid_##i.impulse; \
+                       return; \
+               } \
+               W_SwitchWeapon(this, Weapons_from(WEP_FIRST + i)); \
+       }
+X(0)
+X(1)
+X(2)
+X(3)
+X(4)
+X(5)
+X(6)
+X(7)
+X(8)
+X(9)
+X(10)
+X(11)
+X(12)
+X(13)
+X(14)
+X(15)
+X(16)
+X(17)
+X(18)
+X(19)
+X(20)
+X(21)
+X(22)
+X(23)
+#undef X
+
+IMPULSE(weapon_next_byid)
+{
+       if (this.vehicle) return;
+       if (IS_DEAD(this))
+       {
+               this.impulse = IMP_weapon_next_byid.impulse;
+               return;
+       }
+       W_NextWeapon(this, 0);
+}
+
+IMPULSE(weapon_prev_byid)
+{
+       if (this.vehicle) return;
+       if (IS_DEAD(this))
+       {
+               this.impulse = IMP_weapon_prev_byid.impulse;
+               return;
+       }
+       W_PreviousWeapon(this, 0);
+}
+
+IMPULSE(weapon_next_bygroup)
+{
+       if (this.vehicle) return;
+       if (IS_DEAD(this))
+       {
+               this.impulse = IMP_weapon_next_bygroup.impulse;
+               return;
+       }
+       W_NextWeapon(this, 1);
+}
+
+IMPULSE(weapon_prev_bygroup)
+{
+       if (this.vehicle) return;
+       if (IS_DEAD(this))
+       {
+               this.impulse = IMP_weapon_prev_bygroup.impulse;
+               return;
+       }
+       W_PreviousWeapon(this, 1);
+}
+
+IMPULSE(weapon_next_bypriority)
+{
+       if (this.vehicle) return;
+       if (IS_DEAD(this))
+       {
+               this.impulse = IMP_weapon_next_bypriority.impulse;
+               return;
+       }
+       W_NextWeapon(this, 2);
+}
+
+IMPULSE(weapon_prev_bypriority)
+{
+       if (this.vehicle) return;
+       if (IS_DEAD(this))
+       {
+               this.impulse = IMP_weapon_prev_bypriority.impulse;
+               return;
+       }
+       W_PreviousWeapon(this, 2);
+}
+
+IMPULSE(weapon_last)
+{
+       if (this.vehicle) return;
+       if (IS_DEAD(this)) return;
+       W_LastWeapon(this);
+}
+
+IMPULSE(weapon_best)
+{
+       if (this.vehicle) return;
+       if (IS_DEAD(this)) return;
+       W_SwitchWeapon(this, w_getbestweapon(this));
+}
+
+IMPULSE(weapon_drop)
+{
+       if (this.vehicle) return;
+       if (IS_DEAD(this)) return;
+       W_ThrowWeapon(this, weaponentities[0], W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), '0 0 0', true);
+}
+
+IMPULSE(weapon_reload)
+{
+       if (this.vehicle) return;
+       if (IS_DEAD(this)) return;
+       if (forbidWeaponUse(this)) return;
+       Weapon w = PS(this).m_weapon;
+       entity actor = this;
+       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+       {
+               .entity weaponentity = weaponentities[slot];
+               w.wr_reload(w, actor, weaponentity);
+       }
+}
+
+void ImpulseCommands(entity this)
+{
+       if (gameover) return;
+
+       int imp = this.impulse;
+       if (!imp) return;
+       this.impulse = 0;
+
+       if (MinigameImpulse(this, imp)) return;
+
+       if (timeout_status == TIMEOUT_ACTIVE) return;  // don't allow any impulses while the game is paused
+
+       // allow only weapon change impulses when not in round time
+       if (round_handler_IsActive() && !round_handler_IsRoundStarted())
+       {
+               #define X(id) case IMP_##id.impulse:
+               switch (imp)
+               {
+                       X(weapon_group_0)
+                       X(weapon_group_1)
+                       X(weapon_group_2)
+                       X(weapon_group_3)
+                       X(weapon_group_4)
+                       X(weapon_group_5)
+                       X(weapon_group_6)
+                       X(weapon_group_7)
+                       X(weapon_group_8)
+                       X(weapon_group_9)
+                       X(weapon_next_byid)
+                       X(weapon_prev_byid)
+                       X(weapon_next_bygroup)
+                       X(weapon_prev_bygroup)
+                       X(weapon_next_bypriority)
+                       X(weapon_prev_bypriority)
+                       X(weapon_last)
+                       X(weapon_best)
+                       X(weapon_reload)
+                       X(weapon_priority_0_prev)
+            X(weapon_priority_1_prev)
+            X(weapon_priority_2_prev)
+            X(weapon_priority_3_prev)
+            X(weapon_priority_4_prev)
+            X(weapon_priority_5_prev)
+            X(weapon_priority_6_prev)
+            X(weapon_priority_7_prev)
+            X(weapon_priority_8_prev)
+            X(weapon_priority_9_prev)
+            X(weapon_priority_0_next)
+                       X(weapon_priority_1_next)
+                       X(weapon_priority_2_next)
+                       X(weapon_priority_3_next)
+                       X(weapon_priority_4_next)
+                       X(weapon_priority_5_next)
+                       X(weapon_priority_6_next)
+                       X(weapon_priority_7_next)
+                       X(weapon_priority_8_next)
+                       X(weapon_priority_9_next)
+                       X(weapon_priority_0_best)
+            X(weapon_priority_1_best)
+            X(weapon_priority_2_best)
+            X(weapon_priority_3_best)
+            X(weapon_priority_4_best)
+            X(weapon_priority_5_best)
+            X(weapon_priority_6_best)
+            X(weapon_priority_7_best)
+            X(weapon_priority_8_best)
+            X(weapon_priority_9_best)
+            X(weapon_byid_0)
+            X(weapon_byid_1)
+            X(weapon_byid_2)
+            X(weapon_byid_3)
+            X(weapon_byid_4)
+            X(weapon_byid_5)
+            X(weapon_byid_6)
+            X(weapon_byid_7)
+            X(weapon_byid_8)
+            X(weapon_byid_9)
+            X(weapon_byid_10)
+            X(weapon_byid_11)
+            X(weapon_byid_12)
+            X(weapon_byid_13)
+            X(weapon_byid_14)
+            X(weapon_byid_15)
+            X(weapon_byid_16)
+            X(weapon_byid_17)
+            X(weapon_byid_18)
+            X(weapon_byid_19)
+            X(weapon_byid_20)
+            X(weapon_byid_21)
+            X(weapon_byid_22)
+            X(weapon_byid_23)
+                       break;
+                       default: return;
+               }
+#undef X
+       }
+
+       if (vehicle_impulse(this, imp)) return;
+
+       if (CheatImpulse(this, imp)) return;
+
+       FOREACH(IMPULSES, it.impulse == imp, {
+               void(entity) f = it.impulse_handle;
+               if (!f) continue;
+               f(this);
+               return;
+       });
+}
+
+IMPULSE(use)
+{
+       PlayerUseKey(this);
+}
+
+IMPULSE(waypoint_personal_here)
+{
+       entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.origin, RADARICON_WAYPOINT);
+       if (wp) WaypointSprite_Ping(wp);
+       sprint(this, "personal waypoint spawned at location\n");
+}
+
+IMPULSE(waypoint_personal_crosshair)
+{
+       WarpZone_crosshair_trace(this);
+       entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, trace_endpos, RADARICON_WAYPOINT);
+       if (wp) WaypointSprite_Ping(wp);
+       sprint(this, "personal waypoint spawned at crosshair\n");
+}
+
+IMPULSE(waypoint_personal_death)
+{
+       if (!this.death_origin) return;
+       entity wp = WaypointSprite_DeployPersonal(WP_Waypoint, this, this.death_origin, RADARICON_WAYPOINT);
+       if (wp) WaypointSprite_Ping(wp);
+       sprint(this, "personal waypoint spawned at death location\n");
+}
+
+IMPULSE(waypoint_here_follow)
+{
+       if (!teamplay) return;
+       if (IS_DEAD(this)) return;
+       if (!MUTATOR_CALLHOOK(HelpMePing, this))
+       {
+               entity wp = WaypointSprite_Attach(WP_Helpme, this, true, RADARICON_HELPME);
+               if (!wp) WaypointSprite_HelpMePing(this.waypointsprite_attachedforcarrier);
+               else WaypointSprite_Ping(wp);
+       }
+       sprint(this, "HELP ME attached\n");
+}
+
+IMPULSE(waypoint_here_here)
+{
+       entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.origin, RADARICON_HERE);
+       if (wp) WaypointSprite_Ping(wp);
+       sprint(this, "HERE spawned at location\n");
+}
+
+IMPULSE(waypoint_here_crosshair)
+{
+       WarpZone_crosshair_trace(this);
+       entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, trace_endpos, RADARICON_HERE);
+       if (wp) WaypointSprite_Ping(wp);
+       sprint(this, "HERE spawned at crosshair\n");
+}
+
+IMPULSE(waypoint_here_death)
+{
+       if (!this.death_origin) return;
+       entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, this.death_origin, RADARICON_HERE);
+       if (wp) WaypointSprite_Ping(wp);
+       sprint(this, "HERE spawned at death location\n");
+}
+
+IMPULSE(waypoint_danger_here)
+{
+       entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.origin, RADARICON_DANGER);
+       if (wp) WaypointSprite_Ping(wp);
+       sprint(this, "DANGER spawned at location\n");
+}
+
+IMPULSE(waypoint_danger_crosshair)
+{
+       WarpZone_crosshair_trace(this);
+       entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, trace_endpos, RADARICON_DANGER);
+       if (wp) WaypointSprite_Ping(wp);
+       sprint(this, "DANGER spawned at crosshair\n");
+}
+
+IMPULSE(waypoint_danger_death)
+{
+       if (!this.death_origin) return;
+       entity wp = WaypointSprite_DeployFixed(WP_Danger, false, this, this.death_origin, RADARICON_DANGER);
+       if (wp) WaypointSprite_Ping(wp);
+       sprint(this, "DANGER spawned at death location\n");
+}
+
+IMPULSE(waypoint_clear_personal)
+{
+       WaypointSprite_ClearPersonal(this);
+       if (this.personal)
+       {
+               delete(this.personal);
+               this.personal = NULL;
+       }
+       sprint(this, "personal waypoint cleared\n");
+}
+
+IMPULSE(waypoint_clear)
+{
+       WaypointSprite_ClearOwned(this);
+       if (this.personal)
+       {
+               delete(this.personal);
+               this.personal = NULL;
+       }
+       sprint(this, "all waypoints cleared\n");
+}
+
+IMPULSE(navwaypoint_spawn)
+{
+       if (!autocvar_g_waypointeditor) return;
+       waypoint_schedulerelink(waypoint_spawn(this.origin, this.origin, 0));
+       bprint(strcat("Waypoint spawned at ", vtos(this.origin), "\n"));
+}
+
+IMPULSE(navwaypoint_remove)
+{
+       if (!autocvar_g_waypointeditor) return;
+       entity e = navigation_findnearestwaypoint(this, false);
+       if (!e) return;
+       if (e.wpflags & WAYPOINTFLAG_GENERATED) return;
+       bprint(strcat("Waypoint removed at ", vtos(e.origin), "\n"));
+       waypoint_remove(e);
+}
+
+IMPULSE(navwaypoint_relink)
+{
+       if (!autocvar_g_waypointeditor) return;
+       waypoint_schedulerelinkall();
+}
+
+IMPULSE(navwaypoint_save)
+{
+       if (!autocvar_g_waypointeditor) return;
+       waypoint_saveall();
+}
+
+IMPULSE(navwaypoint_unreachable)
+{
+       if (!autocvar_g_waypointeditor) return;
+       IL_EACH(g_waypoints, true,
+       {
+               it.colormod = '0.5 0.5 0.5';
+               it.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
+       });
+       entity e2 = navigation_findnearestwaypoint(this, false);
+       navigation_markroutes(this, e2);
+
+       int j, m;
+
+       j = 0;
+       m = 0;
+       IL_EACH(g_waypoints, it.wpcost >= 10000000,
+       {
+               LOG_INFO("unreachable: ", etos(it), " ", vtos(it.origin), "\n");
+               it.colormod_z = 8;
+               it.effects |= EF_NODEPTHTEST | EF_BLUE;
+               ++j;
+               ++m;
+       });
+       if (j) LOG_INFOF("%d waypoints cannot be reached from here in any way (marked with blue light)\n", j);
+       navigation_markroutes_inverted(e2);
+
+       j = 0;
+       IL_EACH(g_waypoints, it.wpcost >= 10000000,
+       {
+               LOG_INFO("cannot reach me: ", etos(it), " ", vtos(it.origin), "\n");
+               it.colormod_x = 8;
+               if (!(it.effects & EF_NODEPTHTEST))  // not already reported before
+                       ++m;
+               it.effects |= EF_NODEPTHTEST | EF_RED;
+               ++j;
+       });
+       if (j) LOG_INFOF("%d waypoints cannot walk to here in any way (marked with red light)\n", j);
+       if (m) LOG_INFOF("%d waypoints have been marked total\n", m);
+
+       j = 0;
+       IL_EACH(g_spawnpoints, true,
+       {
+               vector org = it.origin;
+               tracebox(it.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - '0 0 512', MOVE_NOMONSTERS, NULL);
+               setorigin(it, trace_endpos);
+               if (navigation_findnearestwaypoint(it, false))
+               {
+                       setorigin(it, org);
+                       it.effects &= ~EF_NODEPTHTEST;
+                       it.model = "";
+               }
+               else
+               {
+                       setorigin(it, org);
+                       LOG_INFO("spawn without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
+                       it.effects |= EF_NODEPTHTEST;
+                       _setmodel(it, this.model);
+                       it.frame = this.frame;
+                       it.skin = this.skin;
+                       it.colormod = '8 0.5 8';
+                       setsize(it, '0 0 0', '0 0 0');
+                       ++j;
+               }
+       });
+       if (j) LOG_INFOF("%d spawnpoints have no nearest waypoint (marked by player model)\n", j);
+
+       j = 0;
+       IL_EACH(g_items, true,
+       {
+               it.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
+               it.colormod = '0.5 0.5 0.5';
+       });
+       IL_EACH(g_items, true,
+       {
+               if (navigation_findnearestwaypoint(it, false)) continue;
+               LOG_INFO("item without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
+               it.effects |= EF_NODEPTHTEST | EF_RED;
+               it.colormod_x = 8;
+               ++j;
+       });
+       if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked away from (marked with red light)\n", j);
+
+       j = 0;
+       IL_EACH(g_items, true,
+       {
+               if (navigation_findnearestwaypoint(it, true)) continue;
+               LOG_INFO("item without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
+               it.effects |= EF_NODEPTHTEST | EF_BLUE;
+               it.colormod_z = 8;
+               ++j;
+       });
+       if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked to (marked with blue light)\n", j);
+}
diff --git a/qcsrc/server/impulse.qh b/qcsrc/server/impulse.qh
new file mode 100644 (file)
index 0000000..50edc2c
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma once
+
+void ImpulseCommands(entity this);
index 05172241c3e320630e3e4fc02321de3ab370c86f..d33fe87c2e1a477189000119b501b52c6f69c88e 100644 (file)
@@ -1,7 +1,7 @@
 #include "item_key.qh"
 
 #include "../common/triggers/subs.qh"
-#include "../common/monsters/all.qh"
+#include "../common/monsters/_mod.qh"
 #include "../common/notifications/all.qh"
 #include "../common/util.qh"
 #include "../lib/warpzone/util_server.qh"
index b7d26decf53d883dd5f099f7444f6e9a7ed144bb..4d235da694539179a69b46a67bf4e87dd0d42ee2 100644 (file)
@@ -1,6 +1,6 @@
 #include "matrix.qh"
 
-#include "cl_player.qh"
+#include "player.qh"
 
 var void MX_Handle(int buf, string ancestor)
 {
index fa61ab1ab6275caa5d57181765c08af47d433406..4b3d404bf316907a579f6d246330d9f591b257c8 100644 (file)
@@ -4,12 +4,12 @@
 #include "constants.qh"
 #include "g_hook.qh"
 #include "ipban.qh"
-#include "mutators/all.qh"
+#include "mutators/_mod.qh"
 #include "../common/t_items.qh"
 #include "weapons/accuracy.qh"
 #include "weapons/csqcprojectile.qh"
 #include "weapons/selection.qh"
-#include "../common/command/generic.qh"
+#include "../common/command/_mod.qh"
 #include "../common/constants.qh"
 #include "../common/deathtypes/all.qh"
 #include "../common/mapinfo.qh"
 #include "../common/triggers/subs.qh"
 #include "../common/util.qh"
 #include "../common/turrets/sv_turrets.qh"
-#include "../common/weapons/all.qh"
+#include <common/weapons/_all.qh>
 #include "../common/vehicles/sv_vehicles.qh"
 #include "../common/vehicles/vehicle.qh"
-#include "../common/items/all.qc"
+#include "../common/items/_mod.qh"
 #include "../common/state.qh"
 #include "../common/effects/qc/globalsound.qh"
 #include "../lib/csqcmodel/sv_model.qh"
@@ -1144,7 +1144,6 @@ float MoveToRandomLocationWithinBounds(entity e, vector boundmin, vector boundma
 {
     float m, i;
     vector start, org, delta, end, enddown, mstart;
-    entity sp;
 
     m = e.dphitcontentsmask;
     e.dphitcontentsmask = goodcontents | badcontents;
@@ -1200,16 +1199,26 @@ float MoveToRandomLocationWithinBounds(entity e, vector boundmin, vector boundma
             continue;
 
        // rule 4: we must "see" some spawnpoint or item
-       for(sp = NULL; (sp = find(sp, classname, "info_player_deathmatch")); )
-               if(checkpvs(mstart, sp))
-                       if((traceline(mstart, sp.origin, MOVE_NORMAL, e), trace_fraction) >= 1)
-                               break;
+    entity sp = NULL;
+    IL_EACH(g_spawnpoints, checkpvs(mstart, it),
+    {
+       if((traceline(mstart, it.origin, MOVE_NORMAL, e), trace_fraction) >= 1)
+       {
+               sp = it;
+               break;
+       }
+    });
        if(!sp)
        {
-               for(sp = NULL; (sp = findflags(sp, flags, FL_ITEM)); )
-                       if(checkpvs(mstart, sp))
-                               if((traceline(mstart, sp.origin + (sp.mins + sp.maxs) * 0.5, MOVE_NORMAL, e), trace_fraction) >= 1)
-                                       break;
+               IL_EACH(g_items, checkpvs(mstart, it),
+               {
+                       if((traceline(mstart, it.origin + (it.mins + it.maxs) * 0.5, MOVE_NORMAL, e), trace_fraction) >= 1)
+                       {
+                               sp = it;
+                               break;
+                       }
+               });
+
                if(!sp)
                        continue;
        }
index 3d2321896cb5374a8e045bb256c8c4ceba909b50..f0108dec37f6f31717305564d5678040008018d4 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <server/mutators/all.qc>
+#include <server/mutators/loader.qc>
+
+#include <server/mutators/mutator/_mod.inc>
index 8feb1f37d8c2f29a6245bf1e5cc76c845ec06720..9888c94666bfd085a8abe873054f7de7563ea469 100644 (file)
@@ -1,2 +1,4 @@
 // generated file; do not modify
-#include <server/mutators/all.qh>
+#include <server/mutators/loader.qh>
+
+#include <server/mutators/mutator/_mod.qh>
diff --git a/qcsrc/server/mutators/all.inc b/qcsrc/server/mutators/all.inc
deleted file mode 100644 (file)
index 1a80b44..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "mutator/gamemode_assault.qc"
-#include "mutator/gamemode_ca.qc"
-#include "mutator/gamemode_ctf.qc"
-#include "mutator/gamemode_cts.qc"
-#include "mutator/gamemode_deathmatch.qc"
-#include "mutator/gamemode_domination.qc"
-#include "mutator/gamemode_freezetag.qc"
-#include "mutator/gamemode_invasion.qc"
-#include "mutator/gamemode_keepaway.qc"
-#include "mutator/gamemode_keyhunt.qc"
-#include "mutator/gamemode_lms.qc"
-#include "mutator/gamemode_race.qc"
-#include "mutator/gamemode_tdm.qc"
diff --git a/qcsrc/server/mutators/all.qc b/qcsrc/server/mutators/all.qc
deleted file mode 100644 (file)
index 78ba560..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-#include "all.qh"
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-    #include <lib/warpzone/anglestransform.qh>
-    #include <lib/warpzone/common.qh>
-    #include <lib/warpzone/util_server.qh>
-    #include <lib/warpzone/server.qh>
-    #include <common/constants.qh>
-    #include <common/stats.qh>
-    #include <common/teams.qh>
-    #include <common/util.qh>
-    #include <common/command/markup.qh>
-    #include <common/command/rpn.qh>
-    #include <common/command/generic.qh>
-    #include <common/command/command.qh>
-    #include <common/net_notice.qh>
-    #include <common/animdecide.qh>
-    #include <common/monsters/all.qh>
-    #include <common/monsters/sv_monsters.qh>
-    #include <common/monsters/spawn.qh>
-    #include <common/weapons/config.qh>
-    #include <common/weapons/all.qh>
-    #include "../weapons/accuracy.qh"
-    #include "../weapons/common.qh"
-    #include "../weapons/csqcprojectile.qh"
-    #include "../weapons/hitplot.qh"
-    #include "../weapons/selection.qh"
-    #include "../weapons/spawning.qh"
-    #include "../weapons/throwing.qh"
-    #include "../weapons/tracing.qh"
-    #include "../weapons/weaponstats.qh"
-    #include "../weapons/weaponsystem.qh"
-    #include <common/t_items.qh>
-    #include "../autocvars.qh"
-    #include "../constants.qh"
-    #include "../defs.qh"
-    #include <common/notifications/all.qh>
-    #include <common/deathtypes/all.qh>
-    #include "all.qh"
-    #include <common/turrets/sv_turrets.qh>
-    #include <common/vehicles/all.qh>
-    #include "../campaign.qh"
-    #include <common/campaign_common.qh>
-    #include <common/mapinfo.qh>
-    #include "../command/common.qh"
-    #include "../command/banning.qh"
-    #include "../command/radarmap.qh"
-    #include "../command/vote.qh"
-    #include "../command/getreplies.qh"
-    #include "../command/cmd.qh"
-    #include "../command/sv_cmd.qh"
-    #include <common/csqcmodel_settings.qh>
-    #include <lib/csqcmodel/common.qh>
-    #include <lib/csqcmodel/sv_model.qh>
-    #include "../anticheat.qh"
-    #include "../cheats.qh"
-    #include <common/playerstats.qh>
-    #include "../portals.qh"
-    #include "../g_hook.qh"
-    #include "../scores.qh"
-    #include "../spawnpoints.qh"
-    #include "../mapvoting.qh"
-    #include "../ipban.qh"
-    #include "../race.qh"
-    #include "../antilag.qh"
-    #include "../playerdemo.qh"
-    #include "../round_handler.qh"
-    #include "../item_key.qh"
-    #include "../pathlib/pathlib.qh"
-    #include <common/vehicles/all.qh>
-#endif
-
-#include "all.qh"
-
-STATIC_INIT_LATE(Gametype) {
-    Gametype g = MapInfo_CurrentGametype();
-    if (g) {
-        for (string _s = g.m_mutators; _s != ""; _s = cdr(_s)) {
-            string s = car(_s);
-            FOREACH(Mutators, it.m_name == s, LAMBDA(Mutator_Add(it); break));
-        }
-    }
-}
-
-#define IMPLEMENTATION
-#include "all.inc"
-#undef IMPLEMENTATION
diff --git a/qcsrc/server/mutators/all.qh b/qcsrc/server/mutators/all.qh
deleted file mode 100644 (file)
index 4a1f2b3..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-
-#include "mutator.qh"
-#include "gamemode.qh"
-
-#include "all.inc"
index 29b1b7abd4094c7e3e2b269717008e12e2c7936b..7e40b1af1e80daba8461dba1e543dfddd9f3d4ff 100644 (file)
@@ -58,6 +58,7 @@ MUTATOR_HOOKABLE(PlayerDies, EV_PlayerDies);
 /** called when a player dies to e.g. remove stuff he was carrying */
 #define EV_PlayHitsound(i, o) \
     /** victim */ i(entity, MUTATOR_ARGV_0_entity) \
+    /** attacker */ i(entity, MUTATOR_ARGV_1_entity) \
     /**/
 MUTATOR_HOOKABLE(PlayHitsound, EV_PlayHitsound);
 
@@ -359,7 +360,7 @@ MUTATOR_HOOKABLE(W_DecreaseAmmo, EV_W_DecreaseAmmo);
     /**/
 MUTATOR_HOOKABLE(W_Reload, EV_W_Reload);
 
-/** called at the end of player_powerups() in cl_client.qc, used for manipulating the values which are set by powerup items. */
+/** called at the end of player_powerups() in client.qc, used for manipulating the values which are set by powerup items. */
 #define EV_PlayerPowerups(i, o) \
     /** player */    i(entity, MUTATOR_ARGV_0_entity) \
     /** old items */ i(int, MUTATOR_ARGV_1_int) \
@@ -508,7 +509,7 @@ MUTATOR_HOOKABLE(BotShouldAttack, EV_BotShouldAttack);
 MUTATOR_HOOKABLE(PortalTeleport, EV_PortalTeleport);
 
 /**
- * called whenever a player uses impulse 33 (help me) in cl_impulse.qc
+ * called whenever a player uses impulse 33 (help me) in impulse.qc
  * normally help me ping uses .waypointsprite_attachedforcarrier,
  * but if your mutator uses something different then you can handle it
  * in a special manner using this hook
@@ -854,3 +855,11 @@ MUTATOR_HOOKABLE(URI_GetCallback, EV_URI_GetCallback);
     /** player */ i(entity, MUTATOR_ARGV_0_entity) \
     /**/
 MUTATOR_HOOKABLE(ForbidWeaponUse, EV_ForbidWeaponUse);
+
+/** called when creating a clone of the player (usually for corpses that stay after the player has re-spawned) */
+#define EV_CopyBody(i, o) \
+    /** player */               i(entity, MUTATOR_ARGV_0_entity) \
+    /** newly created clone */  i(entity, MUTATOR_ARGV_1_entity) \
+    /** keepvelocity? */        i(bool, MUTATOR_ARGV_2_bool) \
+    /**/
+MUTATOR_HOOKABLE(CopyBody, EV_CopyBody);
index 1e60b203e3caa7226883860198bc9f9e130977df..9a473affdf8bc1f8105cdbc9cef20fca5d8a1cea 100644 (file)
@@ -1,23 +1,87 @@
 #pragma once
 
-#include <server/cl_client.qh>
-#include <server/cl_player.qh>
-#include <server/cl_impulse.qh>
-#include <server/cheats.qh>
-#include <server/g_damage.qh>
 #include <server/g_world.qh>
 #include <server/round_handler.qh>
 #include <server/scores.qh>
 #include <server/scores_rules.qh>
 #include <server/teamplay.qh>
 
-#include <server/bot/api.qh>
+#include "mutator.qh"
 
+// TODO: trim
+
+#include <lib/warpzone/anglestransform.qh>
+#include <lib/warpzone/common.qh>
+#include <lib/warpzone/util_server.qh>
+#include <lib/warpzone/server.qh>
+#include <common/constants.qh>
+#include <common/stats.qh>
+#include <common/teams.qh>
+#include <common/util.qh>
+#include <common/command/_mod.qh>
+#include <common/net_notice.qh>
+#include <common/animdecide.qh>
+#include <common/monsters/_mod.qh>
+#include <common/monsters/sv_monsters.qh>
+#include <common/monsters/sv_spawn.qh>
+#include <common/weapons/config.qh>
+#include <common/weapons/_all.qh>
+#include <server/weapons/accuracy.qh>
+#include <server/weapons/common.qh>
+#include <server/weapons/csqcprojectile.qh>
+#include <server/weapons/hitplot.qh>
+#include <server/weapons/selection.qh>
+#include <server/weapons/spawning.qh>
+#include <server/weapons/throwing.qh>
+#include <server/weapons/tracing.qh>
+#include <server/weapons/weaponstats.qh>
+#include <server/weapons/weaponsystem.qh>
+#include <common/t_items.qh>
+#include <server/autocvars.qh>
+#include <server/constants.qh>
+#include <server/defs.qh>
+#include <common/notifications/all.qh>
+#include <common/deathtypes/all.qh>
+#include <common/turrets/sv_turrets.qh>
+#include <common/vehicles/all.qh>
+#include <server/campaign.qh>
+#include <common/campaign_common.qh>
+#include <common/mapinfo.qh>
+#include <server/command/common.qh>
+#include <server/command/banning.qh>
+#include <server/command/radarmap.qh>
 #include <server/command/vote.qh>
+#include <server/command/getreplies.qh>
+#include <server/command/cmd.qh>
+#include <server/command/sv_cmd.qh>
+#include <common/csqcmodel_settings.qh>
+#include <lib/csqcmodel/common.qh>
+#include <lib/csqcmodel/sv_model.qh>
+#include <server/anticheat.qh>
+#include <server/cheats.qh>
+#include <common/playerstats.qh>
+#include <server/portals.qh>
+#include <server/g_hook.qh>
+#include <server/spawnpoints.qh>
+#include <server/mapvoting.qh>
+#include <server/ipban.qh>
+#include <server/antilag.qh>
+#include <server/playerdemo.qh>
+#include <server/item_key.qh>
+#include <server/pathlib/pathlib.qh>
+#include <common/vehicles/all.qh>
+
+#include <server/client.qh>
+#include <server/player.qh>
+#include <server/impulse.qh>
+#include <server/cheats.qh>
+#include <server/g_damage.qh>
 
-#include <common/monsters/all.qh>
+#include <server/bot/api.qh>
 
-#include <server/command/common.qh>
+#include <server/command/_mod.qh>
+
+#include <common/monsters/_mod.qh>
 
 #include <server/weapons/tracing.qh>
 #include <server/weapons/weaponsystem.qh>
diff --git a/qcsrc/server/mutators/loader.qc b/qcsrc/server/mutators/loader.qc
new file mode 100644 (file)
index 0000000..1784e72
--- /dev/null
@@ -0,0 +1,11 @@
+#include "loader.qh"
+
+STATIC_INIT_LATE(Gametype) {
+    Gametype g = MapInfo_CurrentGametype();
+    if (g) {
+        for (string _s = g.m_mutators; _s != ""; _s = cdr(_s)) {
+            string s = car(_s);
+            FOREACH(Mutators, it.m_name == s, LAMBDA(Mutator_Add(it); break));
+        }
+    }
+}
diff --git a/qcsrc/server/mutators/loader.qh b/qcsrc/server/mutators/loader.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index a63321a36a4731d9253021233886c1e4d9c02e84..e051cd6978dc6da2619fccfa06efc6e1ef2d61be 100644 (file)
@@ -2,9 +2,9 @@
 
 #include <common/mutators/base.qh>
 
-#include <server/cl_client.qh>
-#include <server/cl_player.qh>
-#include <server/cl_impulse.qh>
+#include <server/client.qh>
+#include <server/player.qh>
+#include <server/impulse.qh>
 #include <server/cheats.qh>
 #include <server/g_damage.qh>
 #include <server/round_handler.qh>
@@ -13,8 +13,7 @@
 
 #include <server/bot/api.qh>
 
-#include <server/command/vote.qh>
-#include <server/command/common.qh>
+#include <server/command/_mod.qh>
 
 #include <server/weapons/common.qh>
 #include <server/weapons/tracing.qh>
@@ -28,7 +27,7 @@
 #include <common/stats.qh>
 #include <common/teams.qh>
 
-#include <common/monsters/all.qh>
+#include <common/monsters/_mod.qh>
 
 #include <lib/warpzone/anglestransform.qh>
 #include <lib/warpzone/server.qh>
index 092e07b798be7518b135277dcc4c885bc5093224..f4566a9ca667b305a759e05fcf96edf9dc7c6e4c 100644 (file)
@@ -1,70 +1,5 @@
 #include "gamemode_assault.qh"
-#ifndef GAMEMODE_ASSAULT_H
-#define GAMEMODE_ASSAULT_H
 
-void assault_ScoreRules();
-void ActivateTeamplay();
-
-REGISTER_MUTATOR(as, false)
-{
-       ActivateTeamplay();
-       have_team_spawns = -1; // request team spawns
-
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               assault_ScoreRules();
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back assault_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return 0;
-}
-
-// sprites
-.entity assault_decreaser;
-.entity assault_sprite;
-
-// legacy bot defs
-const int HAVOCBOT_AST_ROLE_NONE = 0;
-const int HAVOCBOT_AST_ROLE_DEFENSE = 2;
-const int HAVOCBOT_AST_ROLE_OFFENSE = 4;
-
-.int havocbot_role_flags;
-.float havocbot_attack_time;
-
-.void(entity this) havocbot_role;
-.void(entity this) havocbot_previous_role;
-
-void(entity this) havocbot_role_ast_defense;
-void(entity this) havocbot_role_ast_offense;
-.entity havocbot_ast_target;
-
-void(entity bot) havocbot_ast_reset_role;
-
-void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrating_items;
-void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
-
-// scoreboard stuff
-const float ST_ASSAULT_OBJECTIVES = 1;
-
-// predefined spawnfuncs
-void target_objective_decrease_activate(entity this);
-#endif
-
-#ifdef IMPLEMENTATION
 .entity sprite;
 
 // random functions
@@ -75,13 +10,10 @@ void assault_objective_use(entity this, entity actor, entity trigger)
        //print("^2Activated objective ", this.targetname, "=", etos(this), "\n");
        //print("Activator is ", actor.classname, "\n");
 
-       for (entity e = NULL; (e = find(e, target, this.targetname)); )
+       IL_EACH(g_assault_objectivedecreasers, it.target == this.targetname,
        {
-               if (e.classname == "target_objective_decrease")
-               {
-                       target_objective_decrease_activate(e);
-               }
-       }
+               target_objective_decrease_activate(it);
+       });
 }
 
 vector target_objective_spawn_evalfunc(entity this, entity player, entity spot, vector current)
@@ -139,16 +71,13 @@ void assault_objective_decrease_use(entity this, entity actor, entity trigger)
 
 void assault_setenemytoobjective(entity this)
 {
-       FOREACH_ENTITY_STRING(targetname, this.target,
+       IL_EACH(g_assault_objectives, it.targetname == this.target,
        {
-               if(it.classname == "target_objective")
-               {
-                       if(this.enemy == NULL)
-                               this.enemy = it;
-                       else
-                               objerror(this, "more than one objective as target - fix the map!");
-                       break;
-               }
+               if(this.enemy == NULL)
+                       this.enemy = it;
+               else
+                       objerror(this, "more than one objective as target - fix the map!");
+               break;
        });
 
        if(this.enemy == NULL)
@@ -215,7 +144,8 @@ void assault_roundstart_use(entity this, entity actor, entity trigger)
        SUB_UseTargets(this, this, trigger);
 
        //(Re)spawn all turrets
-       FOREACH_ENTITY_CLASS("turret_main", true, LAMBDA(
+       IL_EACH(g_turrets, true,
+       {
                // Swap turret teams
                if(it.team == NUM_TEAM_1)
                        it.team = NUM_TEAM_2;
@@ -224,7 +154,7 @@ void assault_roundstart_use(entity this, entity actor, entity trigger)
 
                // Doubles as teamchange
                turret_respawn(it);
-       ));
+       });
 }
 void assault_roundstart_use_this(entity this)
 {
@@ -351,6 +281,7 @@ spawnfunc(target_objective)
        if (!g_assault) { delete(this); return; }
 
        this.classname = "target_objective";
+       IL_PUSH(g_assault_objectives, this);
        this.use = assault_objective_use;
        this.reset = assault_objective_reset;
        this.reset(this);
@@ -362,6 +293,7 @@ spawnfunc(target_objective_decrease)
        if (!g_assault) { delete(this); return; }
 
        this.classname = "target_objective_decrease";
+       IL_PUSH(g_assault_objectivedecreasers, this);
 
        if(!this.dmg)
                this.dmg = 101;
@@ -382,6 +314,7 @@ spawnfunc(func_assault_destructible)
 
        this.spawnflags = 3;
        this.classname = "func_assault_destructible";
+       IL_PUSH(g_assault_destructibles, this);
 
        if(assault_attacker_team == NUM_TEAM_1)
                this.team = NUM_TEAM_2;
@@ -429,17 +362,15 @@ spawnfunc(target_assault_roundstart)
 // legacy bot code
 void havocbot_goalrating_ast_targets(entity this, float ratingscale)
 {
-       FOREACH_ENTITY_CLASS("func_assault_destructible", it.bot_attack,
+       IL_EACH(g_assault_destructibles, it.bot_attack,
        {
                if (it.target == "")
                        continue;
 
                bool found = false;
-               FOREACH_ENTITY_STRING(targetname, it.target,
+               entity destr = it;
+               IL_EACH(g_assault_objectivedecreasers, it.targetname == destr.target,
                {
-                       if(it.classname != "target_objective_decrease")
-                               continue;
-
                        if(it.enemy.health > 0 && it.enemy.health < ASSAULT_VALUE_INACTIVE)
                        {
                                found = true;
@@ -676,5 +607,3 @@ void assault_ScoreRules()
        ScoreInfo_SetLabel_PlayerScore(SP_ASSAULT_OBJECTIVES,    "objectives",      SFL_SORT_PRIO_PRIMARY);
        ScoreRules_basics_end();
 }
-
-#endif
index 399830dad294adb0eb6ca0ca71fe6af6e0976604..43c5100cbca59b949ceaa02ade21107a6aef9898 100644 (file)
@@ -1,3 +1,63 @@
 #pragma once
 
 #include "../gamemode.qh"
+
+void assault_ScoreRules();
+
+REGISTER_MUTATOR(as, false)
+{
+       ActivateTeamplay();
+       have_team_spawns = -1; // request team spawns
+
+       MUTATOR_ONADD
+       {
+               if (time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+               assault_ScoreRules();
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back assault_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return 0;
+}
+
+// sprites
+.entity assault_decreaser;
+.entity assault_sprite;
+
+// legacy bot defs
+const int HAVOCBOT_AST_ROLE_NONE = 0;
+const int HAVOCBOT_AST_ROLE_DEFENSE = 2;
+const int HAVOCBOT_AST_ROLE_OFFENSE = 4;
+
+.int havocbot_role_flags;
+.float havocbot_attack_time;
+
+.void(entity this) havocbot_role;
+.void(entity this) havocbot_previous_role;
+
+void(entity this) havocbot_role_ast_defense;
+void(entity this) havocbot_role_ast_offense;
+.entity havocbot_ast_target;
+
+void(entity bot) havocbot_ast_reset_role;
+
+void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrating_items;
+void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
+
+// scoreboard stuff
+const float ST_ASSAULT_OBJECTIVES = 1;
+
+// predefined spawnfuncs
+void target_objective_decrease_activate(entity this);
index 209c8b85673b09a587379821121c72fe69daf7ca..75c9d600849934b9c2af6c408edea4fb35e63354 100644 (file)
@@ -1,79 +1,5 @@
 #include "gamemode_ca.qh"
-#ifndef GAMEMODE_CA_H
-#define GAMEMODE_CA_H
 
-int autocvar_g_ca_point_limit;
-int autocvar_g_ca_point_leadlimit;
-float autocvar_g_ca_round_timelimit;
-bool autocvar_g_ca_team_spawns;
-int autocvar_g_ca_teams;
-int autocvar_g_ca_teams_override;
-float autocvar_g_ca_warmup;
-
-
-int ca_teams;
-bool allowed_to_spawn;
-
-const int ST_CA_ROUNDS = 1;
-
-bool CA_CheckTeams();
-bool CA_CheckWinner();
-void CA_RoundStart();
-bool ca_isEliminated(entity e);
-
-void SetLimits(int fraglimit_override, int leadlimit_override, float timelimit_override, float qualifying_override);
-
-REGISTER_MUTATOR(ca, false)
-{
-       MUTATOR_ONADD
-       {
-               // game loads at time 1
-               if (time > 1) error("This is a game type and it cannot be added at runtime.");
-
-               allowed_to_spawn = true;
-
-               ca_teams = autocvar_g_ca_teams_override;
-               if (ca_teams < 2) ca_teams = autocvar_g_ca_teams;
-               ca_teams = bound(2, ca_teams, 4);
-
-               int teams = 0;
-               if(ca_teams >= 1) teams |= BIT(0);
-               if(ca_teams >= 2) teams |= BIT(1);
-               if(ca_teams >= 3) teams |= BIT(2);
-               if(ca_teams >= 4) teams |= BIT(3);
-
-               ca_teams = teams; // now set it?
-
-        ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, true);
-        ScoreInfo_SetLabel_TeamScore(ST_CA_ROUNDS, "rounds", SFL_SORT_PRIO_PRIMARY);
-        ScoreRules_basics_end();
-
-               round_handler_Spawn(CA_CheckTeams, CA_CheckWinner, CA_RoundStart);
-               round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
-
-               EliminatedPlayers_Init(ca_isEliminated);
-
-               ActivateTeamplay();
-               SetLimits(autocvar_g_ca_point_limit, autocvar_g_ca_point_leadlimit, autocvar_timelimit_override, -1);
-
-               if (autocvar_g_ca_team_spawns)
-                       have_team_spawns = -1; // request team spawns
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return 0;
-}
-
-// should be removed in the future, as other code should not have to care
-.float caplayer; // 0.5 if scheduled to join the next round
-#endif
-
-#ifdef IMPLEMENTATION
 float autocvar_g_ca_damage2score_multiplier;
 bool autocvar_g_ca_spectate_enemies;
 
@@ -531,5 +457,3 @@ MUTATOR_HOOKFUNCTION(ca, SetWeaponArena)
        // most weapons arena
        if (M_ARGV(0, string) == "0" || M_ARGV(0, string) == "") M_ARGV(0, string) = "most";
 }
-
-#endif
index 399830dad294adb0eb6ca0ca71fe6af6e0976604..8009feb8a569c252694450672b86367b5ced92be 100644 (file)
@@ -1,3 +1,73 @@
 #pragma once
 
 #include "../gamemode.qh"
+
+int autocvar_g_ca_point_limit;
+int autocvar_g_ca_point_leadlimit;
+float autocvar_g_ca_round_timelimit;
+bool autocvar_g_ca_team_spawns;
+int autocvar_g_ca_teams;
+int autocvar_g_ca_teams_override;
+float autocvar_g_ca_warmup;
+
+
+int ca_teams;
+bool allowed_to_spawn;
+
+const int ST_CA_ROUNDS = 1;
+
+bool CA_CheckTeams();
+bool CA_CheckWinner();
+void CA_RoundStart();
+bool ca_isEliminated(entity e);
+
+void SetLimits(int fraglimit_override, int leadlimit_override, float timelimit_override, float qualifying_override);
+
+REGISTER_MUTATOR(ca, false)
+{
+       MUTATOR_ONADD
+       {
+               // game loads at time 1
+               if (time > 1) error("This is a game type and it cannot be added at runtime.");
+
+               allowed_to_spawn = true;
+
+               ca_teams = autocvar_g_ca_teams_override;
+               if (ca_teams < 2) ca_teams = autocvar_g_ca_teams;
+               ca_teams = bound(2, ca_teams, 4);
+
+               int teams = 0;
+               if(ca_teams >= 1) teams |= BIT(0);
+               if(ca_teams >= 2) teams |= BIT(1);
+               if(ca_teams >= 3) teams |= BIT(2);
+               if(ca_teams >= 4) teams |= BIT(3);
+
+               ca_teams = teams; // now set it?
+
+        ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, 0, true);
+        ScoreInfo_SetLabel_TeamScore(ST_CA_ROUNDS, "rounds", SFL_SORT_PRIO_PRIMARY);
+        ScoreRules_basics_end();
+
+               round_handler_Spawn(CA_CheckTeams, CA_CheckWinner, CA_RoundStart);
+               round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
+
+               EliminatedPlayers_Init(ca_isEliminated);
+
+               ActivateTeamplay();
+               SetLimits(autocvar_g_ca_point_limit, autocvar_g_ca_point_leadlimit, autocvar_timelimit_override, -1);
+
+               if (autocvar_g_ca_team_spawns)
+                       have_team_spawns = -1; // request team spawns
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return 0;
+}
+
+// should be removed in the future, as other code should not have to care
+.float caplayer; // 0.5 if scheduled to join the next round
index 9b16e4e96d56ada2e030b4def1ca4b834c09232e..79ac9994625de1b4a1f05da3ad540dee3d75d876 100644 (file)
@@ -1,6 +1,5 @@
 #include "gamemode_ctf.qh"
 
-#ifdef IMPLEMENTATION
 #ifndef CSQC
 void ctf_Initialize();
 
@@ -1235,6 +1234,7 @@ void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag e
        flag.classname = "item_flag_team";
        flag.target = "###item###"; // wut?
        flag.flags = FL_ITEM | FL_NOTARGET;
+       IL_PUSH(g_items, flag);
        flag.solid = SOLID_TRIGGER;
        flag.takedamage = DAMAGE_NO;
        flag.damageforcescale = autocvar_g_ctf_flag_damageforcescale;
@@ -1528,7 +1528,7 @@ void havocbot_goalrating_ctf_droppedflags(entity this, float ratingscale, vector
 
 void havocbot_goalrating_ctf_carrieritems(entity this, float ratingscale, vector org, float sradius)
 {
-       FOREACH_ENTITY_FLOAT(bot_pickup, true,
+       IL_EACH(g_items, it.bot_pickup,
        {
                // gather health and armor only
                if (it.solid)
@@ -2658,5 +2658,3 @@ void ctf_Initialize()
 
        InitializeEntity(NULL, ctf_DelayedInit, INITPRIO_GAMETYPE);
 }
-
-#endif
index a712e033df7414ef7d7a929c3ef0c84bdaaf01ce..4cd8e8767e5f163b58efd886f7e320c8dd66cd71 100644 (file)
@@ -1,47 +1,6 @@
 #include "gamemode_cts.qh"
 #include <server/race.qh>
 
-#ifndef GAMEMODE_CTS_H
-#define GAMEMODE_CTS_H
-
-void cts_Initialize();
-
-REGISTER_MUTATOR(cts, false)
-{
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-
-               g_race_qualifying = true;
-               independent_players = 1;
-               SetLimits(0, 0, autocvar_timelimit_override, -1);
-
-               cts_Initialize();
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back cts_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return 0;
-}
-
-// scores
-const float ST_CTS_LAPS = 1;
-#endif
-
-#ifdef IMPLEMENTATION
-
 #include <server/race.qh>
 
 float autocvar_g_cts_finish_kill_delay;
@@ -59,7 +18,7 @@ void havocbot_role_cts(entity this)
                this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
                navigation_goalrating_start(this);
 
-               FOREACH_ENTITY_CLASS("trigger_race_checkpoint", true,
+               IL_EACH(g_racecheckpoints, true,
                {
                        if(it.cnt == this.race_checkpoint)
                                navigation_routerating(this, it, 1000000, 5000);
@@ -438,5 +397,3 @@ void cts_Initialize()
 {
        cts_ScoreRules();
 }
-
-#endif
index 399830dad294adb0eb6ca0ca71fe6af6e0976604..2a18fe915d4ad85f8999022d834452fb9ef0ff60 100644 (file)
@@ -1,3 +1,39 @@
 #pragma once
 
 #include "../gamemode.qh"
+#include <server/race.qh>
+
+void cts_Initialize();
+
+REGISTER_MUTATOR(cts, false)
+{
+       MUTATOR_ONADD
+       {
+               if (time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+
+               g_race_qualifying = true;
+               independent_players = 1;
+               SetLimits(0, 0, autocvar_timelimit_override, -1);
+
+               cts_Initialize();
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back cts_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return 0;
+}
+
+// scores
+const float ST_CTS_LAPS = 1;
index 866370351377f1dda2c9ac12fa447b8a3ed8f4db..9590027d3f6b6454e8ba2837985ff30663957a07 100644 (file)
@@ -1,37 +1,7 @@
 #include "gamemode_deathmatch.qh"
-#ifndef GAMEMODE_DEATHMATCH_H
-#define GAMEMODE_DEATHMATCH_H
 
-REGISTER_MUTATOR(dm, false)
-{
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back dm_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               error("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return 0;
-}
-
-#endif
-
-#ifdef IMPLEMENTATION
 MUTATOR_HOOKFUNCTION(dm, Scores_CountFragsRemaining)
 {
        // announce remaining frags
        return true;
 }
-#endif
index 399830dad294adb0eb6ca0ca71fe6af6e0976604..d3cc197eafd40efd5ed884c50713e23f746223a8 100644 (file)
@@ -1,3 +1,27 @@
 #pragma once
 
 #include "../gamemode.qh"
+
+REGISTER_MUTATOR(dm, false)
+{
+       MUTATOR_ONADD
+       {
+               if (time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back dm_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               error("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return 0;
+}
index 7c1e81184710c153ae2973b5dab788480320da42..abcae5ada5dffb2db2381386b8a9d0a23627d5b4 100644 (file)
@@ -1,67 +1,4 @@
 #include "gamemode_domination.qh"
-#ifndef GAMEMODE_DOMINATION_H
-#define GAMEMODE_DOMINATION_H
-
-#define autocvar_g_domination_point_limit cvar("g_domination_point_limit")
-bool autocvar_g_domination_roundbased;
-int autocvar_g_domination_roundbased_point_limit;
-int autocvar_g_domination_point_leadlimit;
-
-void dom_Initialize();
-
-REGISTER_MUTATOR(dom, false)
-{
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               dom_Initialize();
-
-               int fraglimit_override = autocvar_g_domination_point_limit;
-               if (autocvar_g_domination_roundbased && autocvar_g_domination_roundbased_point_limit)
-                       fraglimit_override = autocvar_g_domination_roundbased_point_limit;
-
-               ActivateTeamplay();
-               SetLimits(fraglimit_override, autocvar_g_domination_point_leadlimit, autocvar_timelimit_override, -1);
-               have_team_spawns = -1; // request team spawns
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return 0;
-}
-
-// score rule declarations
-const float ST_DOM_TICKS = 1;
-const float ST_DOM_CAPS = 1;
-
-// pps: points per second
-.float dom_total_pps = _STAT(DOM_TOTAL_PPS);
-.float dom_pps_red = _STAT(DOM_PPS_RED);
-.float dom_pps_blue = _STAT(DOM_PPS_BLUE);
-.float dom_pps_yellow = _STAT(DOM_PPS_YELLOW);
-.float dom_pps_pink = _STAT(DOM_PPS_PINK);
-float total_pps;
-float pps_red;
-float pps_blue;
-float pps_yellow;
-float pps_pink;
-
-// capture declarations
-.float enemy_playerid;
-.entity sprite;
-.float captime;
-
-// misc globals
-float domination_roundbased;
-float domination_teams;
-#endif
-
-#ifdef IMPLEMENTATION
 
 #include <server/teamplay.qh>
 
@@ -162,7 +99,8 @@ void dompoint_captured(entity this)
        WaypointSprite_UpdateSprites(this.sprite, msg, WP_Null, WP_Null);
 
        total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
-       FOREACH_ENTITY_CLASS("dom_controlpoint", true, LAMBDA(
+       IL_EACH(g_dompoints, true,
+       {
                if (autocvar_g_domination_point_amt)
                        points = autocvar_g_domination_point_amt;
                else
@@ -179,7 +117,7 @@ void dompoint_captured(entity this)
                        case NUM_TEAM_4: pps_pink += points/wait_time; break;
                }
                total_pps += points/wait_time;
-       ));
+       });
 
        WaypointSprite_UpdateTeamRadar(this.sprite, RADARICON_DOMPOINT, colormapPaletteColor(this.goalentity.team - 1, 0));
        WaypointSprite_Ping(this.sprite);
@@ -346,6 +284,8 @@ void dom_controlpoint_setup(entity this)
        this.nextthink = time;
        settouch(this, dompointtouch);
        this.solid = SOLID_TRIGGER;
+       if(!this.flags & FL_ITEM)
+               IL_PUSH(g_items, this);
        this.flags = FL_ITEM;
        setsize(this, '-32 -32 -32', '32 32 32');
        setorigin(this, this.origin + '0 0 20');
@@ -359,7 +299,7 @@ float total_controlpoints;
 void Domination_count_controlpoints()
 {
        total_controlpoints = redowned = blueowned = yellowowned = pinkowned = 0;
-       FOREACH_ENTITY_CLASS("dom_controlpoint", true,
+       IL_EACH(g_dompoints, true,
        {
                ++total_controlpoints;
                redowned += (it.goalentity.team == NUM_TEAM_1);
@@ -441,6 +381,19 @@ void Domination_RoundStart()
 }
 
 //go to best items, or control points you don't own
+void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius)
+{
+       IL_EACH(g_dompoints, vdist((((it.absmin + it.absmax) * 0.5) - org), <, sradius),
+       {
+               if(it.cnt > -1) // this is just being fought
+                       navigation_routerating(this, it, ratingscale, 5000);
+               else if(it.goalentity.cnt == 0) // unclaimed
+                       navigation_routerating(this, it, ratingscale * 0.5, 5000);
+               else if(it.goalentity.team != this.team) // other team's point
+                       navigation_routerating(this, it, ratingscale * 0.2, 5000);
+       });
+}
+
 void havocbot_role_dom(entity this)
 {
        if(IS_DEAD(this))
@@ -545,6 +498,8 @@ spawnfunc(dom_controlpoint)
        this.effects = this.effects | EF_LOWPRECISION;
        if (autocvar_g_domination_point_fullbright)
                this.effects |= EF_FULLBRIGHT;
+
+       IL_PUSH(g_dompoints, this);
 }
 
 /*QUAKED spawnfunc_dom_team (0 .5 .8) (-32 -32 -24) (32 32 32)
@@ -706,5 +661,3 @@ void dom_Initialize()
        g_domination = true;
        InitializeEntity(NULL, dom_DelayedInit, INITPRIO_GAMETYPE);
 }
-
-#endif
index 9a0a1262f671d75b977df33c8d0dd6bb6104a055..609fcfd0d9f01c91afbe25566948f75f96626219 100644 (file)
@@ -2,4 +2,65 @@
 
 #include "../gamemode.qh"
 
+#define autocvar_g_domination_point_limit cvar("g_domination_point_limit")
+bool autocvar_g_domination_roundbased;
+int autocvar_g_domination_roundbased_point_limit;
+int autocvar_g_domination_point_leadlimit;
+
+void dom_Initialize();
+
+REGISTER_MUTATOR(dom, false)
+{
+       MUTATOR_ONADD
+       {
+               if (time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+               dom_Initialize();
+
+               int fraglimit_override = autocvar_g_domination_point_limit;
+               if (autocvar_g_domination_roundbased && autocvar_g_domination_roundbased_point_limit)
+                       fraglimit_override = autocvar_g_domination_roundbased_point_limit;
+
+               ActivateTeamplay();
+               SetLimits(fraglimit_override, autocvar_g_domination_point_leadlimit, autocvar_timelimit_override, -1);
+               have_team_spawns = -1; // request team spawns
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return 0;
+}
+
+// score rule declarations
+const float ST_DOM_TICKS = 1;
+const float ST_DOM_CAPS = 1;
+
+// pps: points per second
+.float dom_total_pps = _STAT(DOM_TOTAL_PPS);
+.float dom_pps_red = _STAT(DOM_PPS_RED);
+.float dom_pps_blue = _STAT(DOM_PPS_BLUE);
+.float dom_pps_yellow = _STAT(DOM_PPS_YELLOW);
+.float dom_pps_pink = _STAT(DOM_PPS_PINK);
+float total_pps;
+float pps_red;
+float pps_blue;
+float pps_yellow;
+float pps_pink;
+
+// capture declarations
+.float enemy_playerid;
+.entity sprite;
+.float captime;
+
+// misc globals
+float domination_roundbased;
+float domination_teams;
+
 void AnimateDomPoint(entity this);
+
+IntrusiveList g_dompoints;
+STATIC_INIT(g_dompoints) { g_dompoints = IL_NEW(); }
index a875e19ab390bebbaf8a047d6e194ab44b99bf71..cd7372699004bd93fe18e482e69d552e5b24f27d 100644 (file)
@@ -1,58 +1,4 @@
 #include "gamemode_freezetag.qh"
-#ifndef GAMEMODE_FREEZETAG_H
-#define GAMEMODE_FREEZETAG_H
-
-int autocvar_g_freezetag_point_limit;
-int autocvar_g_freezetag_point_leadlimit;
-bool autocvar_g_freezetag_team_spawns;
-void freezetag_Initialize();
-
-REGISTER_MUTATOR(ft, false)
-{
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               freezetag_Initialize();
-
-               ActivateTeamplay();
-               SetLimits(autocvar_g_freezetag_point_limit, autocvar_g_freezetag_point_leadlimit, autocvar_timelimit_override, -1);
-
-               if (autocvar_g_freezetag_team_spawns)
-                       have_team_spawns = -1; // request team spawns
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back freezetag_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return 0;
-}
-
-.float freezetag_frozen_time;
-.float freezetag_frozen_timeout;
-const float ICE_MAX_ALPHA = 1;
-const float ICE_MIN_ALPHA = 0.1;
-float freezetag_teams;
-
-.float reviving; // temp var
-
-float autocvar_g_freezetag_revive_extra_size;
-float autocvar_g_freezetag_revive_speed;
-bool autocvar_g_freezetag_revive_nade;
-float autocvar_g_freezetag_revive_nade_health;
-
-#endif
-#ifdef IMPLEMENTATION
 
 float autocvar_g_freezetag_frozen_maxtime;
 float autocvar_g_freezetag_revive_clearspeed;
@@ -151,6 +97,9 @@ float freezetag_getWinnerTeam()
        return -1; // no player left
 }
 
+void nades_Clear(entity);
+void nades_GiveBonus(entity player, float score);
+
 float freezetag_CheckWinner()
 {
        if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
@@ -385,7 +334,7 @@ MUTATOR_HOOKFUNCTION(ft, PlayerDies)
 {
        entity frag_attacker = M_ARGV(1, entity);
        entity frag_target = M_ARGV(2, entity);
-       float frag_deathtype = M_ARGV(2, float);
+       float frag_deathtype = M_ARGV(3, float);
 
        if(round_handler_IsActive())
        if(round_handler_CountdownRunning())
@@ -637,5 +586,3 @@ void freezetag_Initialize()
 
        EliminatedPlayers_Init(freezetag_isEliminated);
 }
-
-#endif
index 399830dad294adb0eb6ca0ca71fe6af6e0976604..fda0737dd92e1ced1bb5b32923197628fa62dadb 100644 (file)
@@ -1,3 +1,52 @@
 #pragma once
 
 #include "../gamemode.qh"
+
+int autocvar_g_freezetag_point_limit;
+int autocvar_g_freezetag_point_leadlimit;
+bool autocvar_g_freezetag_team_spawns;
+void freezetag_Initialize();
+
+REGISTER_MUTATOR(ft, false)
+{
+       MUTATOR_ONADD
+       {
+               if (time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+               freezetag_Initialize();
+
+               ActivateTeamplay();
+               SetLimits(autocvar_g_freezetag_point_limit, autocvar_g_freezetag_point_leadlimit, autocvar_timelimit_override, -1);
+
+               if (autocvar_g_freezetag_team_spawns)
+                       have_team_spawns = -1; // request team spawns
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back freezetag_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return 0;
+}
+
+.float freezetag_frozen_time;
+.float freezetag_frozen_timeout;
+const float ICE_MAX_ALPHA = 1;
+const float ICE_MIN_ALPHA = 0.1;
+float freezetag_teams;
+
+.float reviving; // temp var
+
+float autocvar_g_freezetag_revive_extra_size;
+float autocvar_g_freezetag_revive_speed;
+bool autocvar_g_freezetag_revive_nade;
+float autocvar_g_freezetag_revive_nade_health;
index 184cf33304f59cbace1f0a0762d9aa47d57ceaa1..2a1b35956b0bce2b42d6b6156629acf93c751683 100644 (file)
@@ -1,72 +1,12 @@
 #include "gamemode_invasion.qh"
-#ifndef GAMEMODE_INVASION_H
-#define GAMEMODE_INVASION_H
 
-#define autocvar_g_invasion_point_limit cvar("g_invasion_point_limit")
-int autocvar_g_invasion_teams;
-bool autocvar_g_invasion_team_spawns;
-bool g_invasion;
-void invasion_Initialize();
-
-REGISTER_MUTATOR(inv, false)
-{
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               g_invasion = true;
-               invasion_Initialize();
-
-               cvar_settemp("g_monsters", "1");
-
-               SetLimits(autocvar_g_invasion_point_limit, autocvar_leadlimit_override, autocvar_timelimit_override, -1);
-               if (autocvar_g_invasion_teams >= 2)
-               {
-                       ActivateTeamplay();
-                       if (autocvar_g_invasion_team_spawns)
-                               have_team_spawns = -1; // request team spawns
-               }
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back invasion_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return 0;
-}
-
-float inv_numspawned;
-float inv_maxspawned;
-float inv_roundcnt;
-float inv_maxrounds;
-float inv_numkilled;
-float inv_lastcheck;
-float inv_maxcurrent;
-
-float invasion_teams;
-float inv_monsters_perteam[17];
-
-float inv_monsterskill;
-
-const float ST_INV_KILLS = 1;
-#endif
-
-#ifdef IMPLEMENTATION
-
-#include <common/monsters/spawn.qh>
+#include <common/monsters/sv_spawn.qh>
 #include <common/monsters/sv_monsters.qh>
 
 #include <server/teamplay.qh>
 
+IntrusiveList g_invasion_spawns;
+STATIC_INIT(g_invasion_spawns) { g_invasion_spawns = IL_NEW(); }
 
 float autocvar_g_invasion_round_timelimit;
 float autocvar_g_invasion_spawnpoint_spawn_delay;
@@ -80,6 +20,7 @@ spawnfunc(invasion_spawnpoint)
        if(!g_invasion) { delete(this); return; }
 
        this.classname = "invasion_spawnpoint";
+       IL_PUSH(g_invasion_spawns, this);
 
        if(autocvar_g_invasion_zombies_only) // precache only if it hasn't been already
        if(this.monsterid) {
@@ -88,24 +29,19 @@ spawnfunc(invasion_spawnpoint)
        }
 }
 
-float invasion_PickMonster(float supermonster_count)
+int invasion_PickMonster(int supermonster_count)
 {
        if(autocvar_g_invasion_zombies_only)
                return MON_ZOMBIE.monsterid;
 
-       float i;
-       entity mon;
-
        RandomSelection_Init();
 
-       for(i = MON_FIRST; i <= MON_LAST; ++i)
+       FOREACH(Monsters, it != MON_Null,
        {
-               mon = get_monsterinfo(i);
-               if((mon.spawnflags & MONSTER_TYPE_FLY) || (mon.spawnflags & MONSTER_TYPE_SWIM) || ((mon.spawnflags & MON_FLAG_SUPERMONSTER) && supermonster_count >= 1))
-                       continue; // flying/swimming monsters not yet supported
-
-               RandomSelection_Add(NULL, i, string_null, 1, 1);
-       }
+               if((it.spawnflags & MONSTER_TYPE_FLY) || (it.spawnflags & MONSTER_TYPE_SWIM) || (it.spawnflags & MONSTER_SIZE_QUAKE) || ((it.spawnflags & MON_FLAG_SUPERMONSTER) && supermonster_count >= 1))
+                       continue;
+        RandomSelection_Add(NULL, it.monsterid, string_null, 1, 1);
+       });
 
        return RandomSelection_chosen_float;
 }
@@ -114,7 +50,7 @@ entity invasion_PickSpawn()
 {
        RandomSelection_Init();
 
-       FOREACH_ENTITY_CLASS("invasion_spawnpoint", true,
+       IL_EACH(g_invasion_spawns, true,
        {
                RandomSelection_Add(it, 0, string_null, 1, ((time >= it.spawnshieldtime) ? 0.2 : 1)); // give recently used spawnpoints a very low rating
                it.spawnshieldtime = time + autocvar_g_invasion_spawnpoint_spawn_delay;
@@ -182,14 +118,14 @@ void invasion_SpawnChosenMonster(float mon)
                monster.spawnflags |= MONSTERFLAG_MINIBOSS; // last round spawns minibosses
 }
 
-void invasion_SpawnMonsters(float supermonster_count)
+void invasion_SpawnMonsters(int supermonster_count)
 {
-       float chosen_monster = invasion_PickMonster(supermonster_count);
+       int chosen_monster = invasion_PickMonster(supermonster_count);
 
        invasion_SpawnChosenMonster(chosen_monster);
 }
 
-float Invasion_CheckWinner()
+bool Invasion_CheckWinner()
 {
        if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
        {
@@ -402,6 +338,8 @@ MUTATOR_HOOKFUNCTION(inv, PlayerSpawn)
 {
        entity player = M_ARGV(0, entity);
 
+       if(player.bot_attack)
+               IL_REMOVE(g_bot_targets, player);
        player.bot_attack = false;
 }
 
@@ -544,5 +482,3 @@ void invasion_Initialize()
 
        InitializeEntity(NULL, invasion_DelayedInit, INITPRIO_GAMETYPE);
 }
-
-#endif
index 399830dad294adb0eb6ca0ca71fe6af6e0976604..e934f8745a4e29bfbcee542ee2c9b1793ea815df 100644 (file)
@@ -1,3 +1,60 @@
 #pragma once
 
 #include "../gamemode.qh"
+
+#define autocvar_g_invasion_point_limit cvar("g_invasion_point_limit")
+int autocvar_g_invasion_teams;
+bool autocvar_g_invasion_team_spawns;
+bool g_invasion;
+void invasion_Initialize();
+
+REGISTER_MUTATOR(inv, false)
+{
+       MUTATOR_ONADD
+       {
+               if (time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+               g_invasion = true;
+               invasion_Initialize();
+
+               cvar_settemp("g_monsters", "1");
+
+               SetLimits(autocvar_g_invasion_point_limit, autocvar_leadlimit_override, autocvar_timelimit_override, -1);
+               if (autocvar_g_invasion_teams >= 2)
+               {
+                       ActivateTeamplay();
+                       if (autocvar_g_invasion_team_spawns)
+                               have_team_spawns = -1; // request team spawns
+               }
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back invasion_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return 0;
+}
+
+float inv_numspawned;
+float inv_maxspawned;
+float inv_roundcnt;
+float inv_maxrounds;
+float inv_numkilled;
+float inv_lastcheck;
+float inv_maxcurrent;
+
+float invasion_teams;
+float inv_monsters_perteam[17];
+
+float inv_monsterskill;
+
+const float ST_INV_KILLS = 1;
index da43b84deb3bb3f1909493c18057cb2c5e6e9d91..6fa76d6c5c1e140fb15382fffbd15118979f8b23 100644 (file)
@@ -1,44 +1,4 @@
 #include "gamemode_keepaway.qh"
-#ifndef GAMEMODE_KEEPAWAY_H
-#define GAMEMODE_KEEPAWAY_H
-
-void ka_Initialize();
-
-REGISTER_MUTATOR(ka, false)
-{
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               ka_Initialize();
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back ka_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return false;
-}
-
-
-entity ka_ball;
-
-void(entity this) havocbot_role_ka_carrier;
-void(entity this) havocbot_role_ka_collector;
-
-void ka_DropEvent(entity plyr);
-#endif
-
-#ifdef IMPLEMENTATION
 
 int autocvar_g_keepaway_ballcarrier_effects;
 float autocvar_g_keepaway_ballcarrier_damage;
@@ -471,6 +431,7 @@ MUTATOR_HOOKFUNCTION(ka, DropSpecialItems)
                ka_DropEvent(frag_target);
 }
 
+.bool pushable;
 
 // ==============
 // Initialization
@@ -490,6 +451,7 @@ void ka_SpawnBall() // loads various values for the ball, runs only once at star
        e.glow_color = autocvar_g_keepawayball_trail_color;
        e.glow_trail = true;
        e.flags = FL_ITEM;
+       IL_PUSH(g_items, e);
        e.pushable = true;
        e.reset = ka_Reset;
        settouch(e, ka_TouchEvent);
@@ -513,5 +475,3 @@ void ka_Initialize() // run at the start of a match, initiates game mode
        ka_ScoreRules();
        ka_SpawnBall();
 }
-
-#endif
index 399830dad294adb0eb6ca0ca71fe6af6e0976604..a13ab83a555089681bd43974e221421980665c14 100644 (file)
@@ -1,3 +1,38 @@
 #pragma once
 
 #include "../gamemode.qh"
+
+void ka_Initialize();
+
+REGISTER_MUTATOR(ka, false)
+{
+       MUTATOR_ONADD
+       {
+               if (time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+               ka_Initialize();
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back ka_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return false;
+}
+
+
+entity ka_ball;
+
+void(entity this) havocbot_role_ka_carrier;
+void(entity this) havocbot_role_ka_collector;
+
+void ka_DropEvent(entity plyr);
index 5f6b5226d413d7f03e237eb0277adf4fe8dda037..0e5d7bd02a6ca2f3e63ecce293067c6f59211da1 100644 (file)
@@ -1,58 +1,4 @@
 #include "gamemode_keyhunt.qh"
-#ifndef GAMEMODE_KEYHUNT_H
-#define GAMEMODE_KEYHUNT_H
-
-#define autocvar_g_keyhunt_point_limit cvar("g_keyhunt_point_limit")
-int autocvar_g_keyhunt_point_leadlimit;
-bool autocvar_g_keyhunt_team_spawns;
-void kh_Initialize();
-
-REGISTER_MUTATOR(kh, false)
-{
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               kh_Initialize();
-
-               ActivateTeamplay();
-               SetLimits(autocvar_g_keyhunt_point_limit, autocvar_g_keyhunt_point_leadlimit, autocvar_timelimit_override, -1);
-               if (autocvar_g_keyhunt_team_spawns)
-                       have_team_spawns = -1; // request team spawns
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back kh_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return 0;
-}
-
-#define FOR_EACH_KH_KEY(v) for(v = kh_worldkeylist; v; v = v.kh_worldkeynext )
-
-// ALL OF THESE should be removed in the future, as other code should not have to care
-
-// used by bots:
-float kh_tracking_enabled;
-.entity kh_next;
-float kh_Key_AllOwnedByWhichTeam();
-
-USING(kh_Think_t, void());
-void kh_StartRound();
-void kh_Controller_SetThink(float t, kh_Think_t func);
-
-#endif
-
-#ifdef IMPLEMENTATION
 
 float autocvar_g_balance_keyhunt_damageforcescale;
 float autocvar_g_balance_keyhunt_delay_collect;
@@ -298,6 +244,7 @@ void kh_Key_Attach(entity key)  // runs when a player picks up a key and several
        key.angles_y -= key.owner.angles.y;
 #endif
        key.flags = 0;
+       IL_REMOVE(g_items, key);
        key.solid = SOLID_NOT;
        set_movetype(key, MOVETYPE_NONE);
        key.team = key.owner.team;
@@ -337,6 +284,7 @@ void kh_Key_Detach(entity key) // runs every time a key is dropped or lost. Runs
        key.angles_y += key.owner.angles.y;
 #endif
        key.flags = FL_ITEM;
+       IL_PUSH(g_items, key);
        key.solid = SOLID_TRIGGER;
        set_movetype(key, MOVETYPE_TOSS);
        key.pain_finished = time + autocvar_g_balance_keyhunt_delay_return;
@@ -475,7 +423,7 @@ void kh_Key_Damage(entity this, entity inflictor, entity attacker, float damage,
                // immediately return is bad
                // maybe start a shorter countdown?
        }
-       if(vlen(force) <= 0)
+       if(force == '0 0 0')
                return;
        if(time > this.pushltime)
                if(IS_PLAYER(attacker))
@@ -570,6 +518,8 @@ void kh_FinishRound()  // runs when a team captures the keys
        kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round, kh_StartRound);
 }
 
+void nades_GiveBonus(entity player, float score);
+
 void kh_WinnerTeam(float teem)  // runs when a team wins // Samual: Teem?.... TEEM?!?! what the fuck is wrong with you people
 {
        // all key carriers get some points
@@ -577,8 +527,8 @@ void kh_WinnerTeam(float teem)  // runs when a team wins // Samual: Teem?.... TE
        float first;
        entity key;
        float score;
-       score = (kh_teams - 1) * autocvar_g_balance_keyhunt_score_capture;
-       DistributeEvenly_Init(score, kh_teams);
+       score = (NumTeams(kh_teams) - 1) * autocvar_g_balance_keyhunt_score_capture;
+       DistributeEvenly_Init(score, NumTeams(kh_teams));
        // twice the score for 3 team games, three times the score for 4 team games!
        // note: for a win by destroying the key, this should NOT be applied
        FOR_EACH_KH_KEY(key)
@@ -622,11 +572,11 @@ void kh_WinnerTeam(float teem)  // runs when a team wins // Samual: Teem?.... TE
                        firstorigin = thisorigin;
                first = false;
        }
-       if(kh_teams > 2)
+       if(NumTeams(kh_teams) > 2)
        {
                te_lightning2(NULL, lastorigin, firstorigin);
        }
-       midpoint = midpoint * (1 / kh_teams);
+       midpoint = midpoint * (1 / NumTeams(kh_teams));
        te_customflash(midpoint, 1000, 1, Team_ColorRGB(teem) * 0.5 + '0.5 0.5 0.5');  // make the color >=0.5 in each component
 
        play2all(SND(KH_CAPTURE));
@@ -687,8 +637,8 @@ void kh_LoserTeam(float teem, entity lostkey)  // runs when a player pushes a fl
                fragsleft = DistributeEvenly_Get(players);
 
                // Now distribute these among all other teams...
-               j = kh_teams - 1;
-               for(i = 0; i < kh_teams; ++i)
+               j = NumTeams(kh_teams) - 1;
+               for(i = 0; i < NumTeams(kh_teams); ++i)
                {
                        thisteam = kh_Team_ByID(i);
                        if(thisteam == teem) // bad boy, no cookie - this WILL happen
@@ -839,7 +789,7 @@ float kh_Key_AllOwnedByWhichTeam()  // constantly called. check to see if all th
        float keys;
 
        teem = -1;
-       keys = kh_teams;
+       keys = NumTeams(kh_teams);
        FOR_EACH_KH_KEY(key)
        {
                if(!key.owner)
@@ -907,7 +857,7 @@ void kh_Key_DropAll(entity player, float suicide) // runs whenever a player dies
 
 float kh_CheckPlayers(float num)
 {
-       if(num < kh_teams)
+       if(num < NumTeams(kh_teams))
        {
                float t_team = kh_Team_ByID(num);
                float players = 0;
@@ -921,8 +871,8 @@ float kh_CheckPlayers(float num)
        return 0;
 }
 
-#define KH_READY_TEAMS() (!p1 + !p2 + ((kh_teams >= 3) ? !p3 : p3) + ((kh_teams >= 4) ? !p4 : p4))
-#define KH_READY_TEAMS_OK() (KH_READY_TEAMS() == kh_teams)
+#define KH_READY_TEAMS() (!p1 + !p2 + ((NumTeams(kh_teams) >= 3) ? !p3 : p3) + ((NumTeams(kh_teams) >= 4) ? !p4 : p4))
+#define KH_READY_TEAMS_OK() (KH_READY_TEAMS() == NumTeams(kh_teams))
 void kh_WaitForPlayers()  // delay start of the round until enough players are present
 {
        if(time < game_starttime)
@@ -998,7 +948,7 @@ void kh_StartRound()  // runs at the start of each round
        Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_KEYHUNT);
        Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_KEYHUNT_OTHER);
 
-       for(i = 0; i < kh_teams; ++i)
+       for(i = 0; i < NumTeams(kh_teams); ++i)
        {
                teem = kh_Team_ByID(i);
                players = 0;
@@ -1011,7 +961,7 @@ void kh_StartRound()  // runs at the start of each round
                                        my_player = it;
                        }
                ));
-               kh_Key_Spawn(my_player, 360 * i / kh_teams, i);
+               kh_Key_Spawn(my_player, 360 * i / NumTeams(kh_teams), i);
        }
 
        kh_tracking_enabled = false;
@@ -1392,5 +1342,3 @@ MUTATOR_HOOKFUNCTION(kh, reset_map_global)
 {
        kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round + (game_starttime - time), kh_StartRound);
 }
-
-#endif
index 399830dad294adb0eb6ca0ca71fe6af6e0976604..9a98df98fda007eee44fc3e982da116b8a3584d2 100644 (file)
@@ -1,3 +1,51 @@
 #pragma once
 
 #include "../gamemode.qh"
+
+#define autocvar_g_keyhunt_point_limit cvar("g_keyhunt_point_limit")
+int autocvar_g_keyhunt_point_leadlimit;
+bool autocvar_g_keyhunt_team_spawns;
+void kh_Initialize();
+
+REGISTER_MUTATOR(kh, false)
+{
+       MUTATOR_ONADD
+       {
+               if (time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+               kh_Initialize();
+
+               ActivateTeamplay();
+               SetLimits(autocvar_g_keyhunt_point_limit, autocvar_g_keyhunt_point_leadlimit, autocvar_timelimit_override, -1);
+               if (autocvar_g_keyhunt_team_spawns)
+                       have_team_spawns = -1; // request team spawns
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back kh_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return 0;
+}
+
+#define FOR_EACH_KH_KEY(v) for(v = kh_worldkeylist; v; v = v.kh_worldkeynext )
+
+// ALL OF THESE should be removed in the future, as other code should not have to care
+
+// used by bots:
+float kh_tracking_enabled;
+.entity kh_next;
+float kh_Key_AllOwnedByWhichTeam();
+
+USING(kh_Think_t, void());
+void kh_StartRound();
+void kh_Controller_SetThink(float t, kh_Think_t func);
index afd107bc43298c08e5d617a3f924c697b386826d..608517fbffc99e838903461d3b81201d893bf447 100644 (file)
@@ -1,49 +1,8 @@
 #include "gamemode_lms.qh"
-#ifndef GAMEMODE_LMS_H
-#define GAMEMODE_LMS_H
-
-#define autocvar_g_lms_lives_override cvar("g_lms_lives_override")
-void lms_Initialize();
-
-REGISTER_MUTATOR(lms, false)
-{
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               lms_Initialize();
-
-               SetLimits(((!autocvar_g_lms_lives_override) ? -1 : autocvar_g_lms_lives_override), 0, autocvar_timelimit_override, -1);
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back lms_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return 0;
-}
-
-// lives related defs
-float lms_lowest_lives;
-float lms_next_place;
-float LMS_NewPlayerLives();
-
-#endif
-
-#ifdef IMPLEMENTATION
 
 #include <common/mutators/mutator/instagib/items.qc>
 #include <server/campaign.qh>
-#include <server/command/cmd.qh>
+#include <server/command/_mod.qh>
 
 int autocvar_g_lms_extra_lives;
 bool autocvar_g_lms_join_anytime;
@@ -408,6 +367,3 @@ void lms_Initialize()
 
        lms_ScoreRules();
 }
-
-
-#endif
index 399830dad294adb0eb6ca0ca71fe6af6e0976604..7bf012668efb075a468a8e536fd405fb0d9e85ce 100644 (file)
@@ -1,3 +1,38 @@
 #pragma once
 
 #include "../gamemode.qh"
+
+#define autocvar_g_lms_lives_override cvar("g_lms_lives_override")
+void lms_Initialize();
+
+REGISTER_MUTATOR(lms, false)
+{
+       MUTATOR_ONADD
+       {
+               if (time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+               lms_Initialize();
+
+               SetLimits(((!autocvar_g_lms_lives_override) ? -1 : autocvar_g_lms_lives_override), 0, autocvar_timelimit_override, -1);
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back lms_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return 0;
+}
+
+// lives related defs
+float lms_lowest_lives;
+float lms_next_place;
+float LMS_NewPlayerLives();
index 04561db369e806d5d6d227d49f56614680bb7f8c..b791a69dce9830cc42b45743501dce63bbc80ff1 100644 (file)
@@ -1,42 +1,5 @@
 #include "gamemode_race.qh"
 
-#ifndef GAMEMODE_RACE_H
-#define GAMEMODE_RACE_H
-
-void rc_SetLimits();
-void race_Initialize();
-
-REGISTER_MUTATOR(rc, false)
-{
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-
-               rc_SetLimits();
-               race_Initialize();
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back race_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return 0;
-}
-
-#endif
-
-#ifdef IMPLEMENTATION
-
 #include <server/race.qh>
 
 #define autocvar_g_race_laps_limit cvar("g_race_laps_limit")
@@ -51,23 +14,22 @@ void havocbot_role_race(entity this)
        if(IS_DEAD(this))
                return;
 
-       entity e;
        if (this.bot_strategytime < time)
        {
                this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
                navigation_goalrating_start(this);
 
-               for(e = NULL; (e = find(e, classname, "trigger_race_checkpoint")) != NULL; )
+               IL_EACH(g_racecheckpoints, true,
                {
-                       if(e.cnt == this.race_checkpoint)
+                       if(it.cnt == this.race_checkpoint)
                        {
-                               navigation_routerating(this, e, 1000000, 5000);
+                               navigation_routerating(this, it, 1000000, 5000);
                        }
                        else if(this.race_checkpoint == -1)
                        {
-                               navigation_routerating(this, e, 1000000, 5000);
+                               navigation_routerating(this, it, 1000000, 5000);
                        }
-               }
+               });
 
                navigation_goalrating_end(this);
        }
@@ -505,5 +467,3 @@ void rc_SetLimits()
                g_race_qualifying = 0;
        SetLimits(fraglimit_override, leadlimit_override, timelimit_override, qualifying_override);
 }
-
-#endif
index 399830dad294adb0eb6ca0ca71fe6af6e0976604..ec71a62d178483d2277228801751f147d721504d 100644 (file)
@@ -1,3 +1,33 @@
 #pragma once
 
 #include "../gamemode.qh"
+
+void rc_SetLimits();
+void race_Initialize();
+
+REGISTER_MUTATOR(rc, false)
+{
+       MUTATOR_ONADD
+       {
+               if (time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+
+               rc_SetLimits();
+               race_Initialize();
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back race_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return 0;
+}
index 8fdfc83433b57e9251f0ec18ecf3c9a42a9b74a6..d906c1988c247c6bf4f4353da149d31006e5e192 100644 (file)
@@ -1,45 +1,5 @@
 #include "gamemode_tdm.qh"
-#ifndef GAMEMODE_TDM_H
-#define GAMEMODE_TDM_H
 
-int autocvar_g_tdm_point_limit;
-int autocvar_g_tdm_point_leadlimit;
-bool autocvar_g_tdm_team_spawns;
-void tdm_DelayedInit(entity this);
-
-REGISTER_MUTATOR(tdm, false)
-{
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               InitializeEntity(NULL, tdm_DelayedInit, INITPRIO_GAMETYPE);
-
-               ActivateTeamplay();
-               SetLimits(autocvar_g_tdm_point_limit, autocvar_g_tdm_point_leadlimit, autocvar_timelimit_override, -1);
-               if (autocvar_g_tdm_team_spawns)
-                       have_team_spawns = -1; // request team spawns
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back tdm_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return 0;
-}
-
-#endif
-
-#ifdef IMPLEMENTATION
 int autocvar_g_tdm_teams;
 int autocvar_g_tdm_teams_override;
 
@@ -108,5 +68,3 @@ MUTATOR_HOOKFUNCTION(tdm, Scores_CountFragsRemaining)
        // announce remaining frags
        return true;
 }
-
-#endif
index 399830dad294adb0eb6ca0ca71fe6af6e0976604..e7efbae7f5b13a9930a3a0523f61dc9d5fe0b6b6 100644 (file)
@@ -1,3 +1,38 @@
 #pragma once
 
 #include "../gamemode.qh"
+
+int autocvar_g_tdm_point_limit;
+int autocvar_g_tdm_point_leadlimit;
+bool autocvar_g_tdm_team_spawns;
+void tdm_DelayedInit(entity this);
+
+REGISTER_MUTATOR(tdm, false)
+{
+       MUTATOR_ONADD
+       {
+               if (time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+               InitializeEntity(NULL, tdm_DelayedInit, INITPRIO_GAMETYPE);
+
+               ActivateTeamplay();
+               SetLimits(autocvar_g_tdm_point_limit, autocvar_g_tdm_point_leadlimit, autocvar_timelimit_override, -1);
+               if (autocvar_g_tdm_team_spawns)
+                       have_team_spawns = -1; // request team spawns
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back tdm_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return 0;
+}
diff --git a/qcsrc/server/pathlib/_all.inc b/qcsrc/server/pathlib/_all.inc
deleted file mode 100644 (file)
index 7a06615..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef DEBUGPATHING
-       #define DEBUGPATHING 0
-#endif
-
-#include "costs.qc"
-#include "expandnode.qc"
-#include "main.qc"
-#include "movenode.qc"
-#include "path_waypoint.qc"
-#include "utility.qc"
-#if DEBUGPATHING
-       #include "debug.qc"
-#endif
index 6b89bb640223c1776d48cf5f152f285789258868..fdb95d2f608b967be48675f96e549975693e766e 100644 (file)
@@ -1,5 +1,4 @@
 #include "costs.qh"
-#include "pathlib.qh"
 
 float pathlib_g_static(entity parent,vector to, float static_cost)
 {
index 6f70f09beec2219624baeca92e2cd7deaa104fb4..811c031aff3d968a056e6dffa974179a409ce321 100644 (file)
@@ -1 +1,2 @@
 #pragma once
+#include "pathlib.qh"
index 0a350df2c2f467f4ed03958639fd31607b7dd133..b84ae6414e20ba637d8f81c86bf946040bf37cb5 100644 (file)
@@ -1,5 +1,6 @@
 #include "debug.qh"
-#include "pathlib.qh"
+
+#if DEBUGPATHING
 
 MODEL(SQUARE,       "models/pathlib/square.md3");
 MODEL(SQUARE_GOOD,  "models/pathlib/goodsquare.md3");
@@ -119,3 +120,5 @@ void pathlib_showedge(vector where,float _lifetime,float rot)
     //e.angles_x += 90;
 
 }
+
+#endif
index 6f70f09beec2219624baeca92e2cd7deaa104fb4..811c031aff3d968a056e6dffa974179a409ce321 100644 (file)
@@ -1 +1,2 @@
 #pragma once
+#include "pathlib.qh"
index 339a2e7e0e43c73346741e002c58621874ed9864..4ae0c2c86d4b5f0f2970cf9fdcda76393dfb84bc 100644 (file)
@@ -1,5 +1,9 @@
 #pragma once
 
+#ifndef DEBUGPATHING
+       #define DEBUGPATHING 0
+#endif
+
 .entity pathlib_list;
 .entity path_next;
 .entity path_prev;
diff --git a/qcsrc/server/player.qc b/qcsrc/server/player.qc
new file mode 100644 (file)
index 0000000..e95ae98
--- /dev/null
@@ -0,0 +1,966 @@
+#include "player.qh"
+
+#include "bot/api.qh"
+#include "cheats.qh"
+#include "g_damage.qh"
+#include "g_subs.qh"
+#include "miscfunctions.qh"
+#include "portals.qh"
+#include "teamplay.qh"
+#include "weapons/throwing.qh"
+#include "command/common.qh"
+#include "../common/state.qh"
+#include "../common/anim.qh"
+#include "../common/animdecide.qh"
+#include "../common/csqcmodel_settings.qh"
+#include "../common/deathtypes/all.qh"
+#include "../common/triggers/subs.qh"
+#include "../common/playerstats.qh"
+#include "../lib/csqcmodel/sv_model.qh"
+
+#include "../common/minigames/sv_minigames.qh"
+
+#include "../common/physics/player.qh"
+#include "../common/effects/qc/all.qh"
+#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
+#include "../common/triggers/include.qh"
+
+#include "weapons/weaponstats.qh"
+
+#include "../common/animdecide.qh"
+
+void Drop_Special_Items(entity player)
+{
+       // called when the player has become stuck or frozen
+       // so objective items aren't stuck with the player
+
+       MUTATOR_CALLHOOK(DropSpecialItems, player);
+}
+
+void CopyBody_Think(entity this)
+{
+       if(this.CopyBody_nextthink && time > this.CopyBody_nextthink)
+       {
+               this.CopyBody_think(this);
+               if(wasfreed(this))
+                       return;
+               this.CopyBody_nextthink = this.nextthink;
+               this.CopyBody_think = getthink(this);
+               setthink(this, CopyBody_Think);
+       }
+       CSQCMODEL_AUTOUPDATE(this);
+       this.nextthink = time;
+}
+void CopyBody(entity this, float keepvelocity)
+{
+       if (this.effects & EF_NODRAW)
+               return;
+       entity clone = new(body);
+       clone.enemy = this;
+       clone.lip = this.lip;
+       clone.colormap = this.colormap;
+       clone.iscreature = this.iscreature;
+       clone.teleportable = this.teleportable;
+       clone.damagedbycontents = this.damagedbycontents;
+       clone.angles = this.angles;
+       clone.v_angle = this.v_angle;
+       clone.avelocity = this.avelocity;
+       clone.damageforcescale = this.damageforcescale;
+       clone.effects = this.effects;
+       clone.glowmod = this.glowmod;
+       clone.event_damage = this.event_damage;
+       clone.anim_state = this.anim_state;
+       clone.anim_time = this.anim_time;
+       clone.anim_lower_action = this.anim_lower_action;
+       clone.anim_lower_time = this.anim_lower_time;
+       clone.anim_upper_action = this.anim_upper_action;
+       clone.anim_upper_time = this.anim_upper_time;
+       clone.anim_implicit_state = this.anim_implicit_state;
+       clone.anim_implicit_time = this.anim_implicit_time;
+       clone.anim_lower_implicit_action = this.anim_lower_implicit_action;
+       clone.anim_lower_implicit_time = this.anim_lower_implicit_time;
+       clone.anim_upper_implicit_action = this.anim_upper_implicit_action;
+       clone.anim_upper_implicit_time = this.anim_upper_implicit_time;
+       clone.dphitcontentsmask = this.dphitcontentsmask;
+       clone.death_time = this.death_time;
+       clone.pain_finished = this.pain_finished;
+       clone.health = this.health;
+       clone.armorvalue = this.armorvalue;
+       clone.armortype = this.armortype;
+       clone.model = this.model;
+       clone.modelindex = this.modelindex;
+       clone.skin = this.skin;
+       clone.species = this.species;
+       clone.move_qcphysics = false; // don't run gamecode logic on clones, too many
+       set_movetype(clone, this.move_movetype);
+       clone.solid = this.solid;
+       clone.ballistics_density = this.ballistics_density;
+       clone.takedamage = this.takedamage;
+       setcefc(clone, getcefc(this));
+       clone.uncustomizeentityforclient = this.uncustomizeentityforclient;
+       clone.uncustomizeentityforclient_set = this.uncustomizeentityforclient_set;
+       if (keepvelocity == 1)
+               clone.velocity = this.velocity;
+       clone.oldvelocity = clone.velocity;
+       clone.alpha = this.alpha;
+       clone.fade_time = this.fade_time;
+       clone.fade_rate = this.fade_rate;
+       //clone.weapon = this.weapon;
+       setorigin(clone, this.origin);
+       setsize(clone, this.mins, this.maxs);
+       clone.prevorigin = this.origin;
+       clone.reset = SUB_Remove;
+       clone._ps = this._ps;
+
+       Drag_MoveDrag(this, clone);
+
+       if(clone.colormap <= maxclients && clone.colormap > 0)
+               clone.colormap = 1024 + this.clientcolors;
+
+       CSQCMODEL_AUTOINIT(clone);
+       clone.CopyBody_nextthink = this.nextthink;
+       clone.CopyBody_think = getthink(this);
+       clone.nextthink = time;
+       setthink(clone, CopyBody_Think);
+       // "bake" the current animation frame for clones (they don't get clientside animation)
+       animdecide_load_if_needed(clone);
+       animdecide_setframes(clone, false, frame, frame1time, frame2, frame2time);
+
+       IL_PUSH(g_clones, clone);
+
+       MUTATOR_CALLHOOK(CopyBody, this, clone, keepvelocity);
+}
+
+void player_setupanimsformodel(entity this)
+{
+       // load animation info
+       animdecide_load_if_needed(this);
+       animdecide_setstate(this, 0, false);
+}
+
+void player_anim(entity this)
+{
+       int deadbits = (this.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2));
+       if(IS_DEAD(this)) {
+               if (!deadbits) {
+                       // Decide on which death animation to use.
+                       if(random() < 0.5)
+                               deadbits = ANIMSTATE_DEAD1;
+                       else
+                               deadbits = ANIMSTATE_DEAD2;
+               }
+       } else {
+               // Clear a previous death animation.
+               deadbits = 0;
+       }
+       int animbits = deadbits;
+       if(STAT(FROZEN, this))
+               animbits |= ANIMSTATE_FROZEN;
+       if(this.move_movetype == MOVETYPE_FOLLOW)
+               animbits |= ANIMSTATE_FOLLOW;
+       if(this.crouch)
+               animbits |= ANIMSTATE_DUCK;
+       animdecide_setstate(this, animbits, false);
+       animdecide_setimplicitstate(this, IS_ONGROUND(this));
+}
+
+void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{
+       float take, save;
+       vector v;
+       Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, this, attacker);
+
+       // damage resistance (ignore most of the damage from a bullet or similar)
+       damage = max(damage - 5, 1);
+
+       v = healtharmor_applydamage(this.armorvalue, autocvar_g_balance_armor_blockpercent, deathtype, damage);
+       take = v.x;
+       save = v.y;
+
+       if(sound_allowed(MSG_BROADCAST, attacker))
+       {
+               if (save > 10)
+                       sound (this, CH_SHOTS, SND_ARMORIMPACT, VOL_BASE, ATTEN_NORM);
+               else if (take > 30)
+                       sound (this, CH_SHOTS, SND_BODYIMPACT2, VOL_BASE, ATTEN_NORM);
+               else if (take > 10)
+                       sound (this, CH_SHOTS, SND_BODYIMPACT1, VOL_BASE, ATTEN_NORM);
+       }
+
+       if (take > 50)
+               Violence_GibSplash_At(hitloc, force * -0.1, 3, 1, this, attacker);
+       if (take > 100)
+               Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, this, attacker);
+
+       this.armorvalue = this.armorvalue - save;
+       this.health = this.health - take;
+       // pause regeneration for 5 seconds
+       this.pauseregen_finished = max(this.pauseregen_finished, time + autocvar_g_balance_pause_health_regen);
+
+       this.dmg_save = this.dmg_save + save;//max(save - 10, 0);
+       this.dmg_take = this.dmg_take + take;//max(take - 10, 0);
+       this.dmg_inflictor = inflictor;
+
+       if (this.health <= -autocvar_sv_gibhealth && this.alpha >= 0)
+       {
+               // don't use any animations as a gib
+               this.frame = 0;
+               // view just above the floor
+               this.view_ofs = '0 0 4';
+
+               Violence_GibSplash(this, 1, 1, attacker);
+               this.alpha = -1;
+               this.solid = SOLID_NOT; // restore later
+               this.takedamage = DAMAGE_NO; // restore later
+               this.damagedbycontents = false;
+       }
+}
+
+void calculate_player_respawn_time(entity this)
+{
+       if(g_ca)
+               return;
+
+       float gametype_setting_tmp;
+       float sdelay_max = GAMETYPE_DEFAULTED_SETTING(respawn_delay_max);
+       float sdelay_small = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small);
+       float sdelay_large = GAMETYPE_DEFAULTED_SETTING(respawn_delay_large);
+       float sdelay_small_count = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small_count);
+       float sdelay_large_count = GAMETYPE_DEFAULTED_SETTING(respawn_delay_large_count);
+       float waves = GAMETYPE_DEFAULTED_SETTING(respawn_waves);
+
+       float pcount = 1;  // Include myself whether or not team is already set right and I'm a "player".
+       if (teamplay)
+       {
+               FOREACH_CLIENT(IS_PLAYER(it) && it != this, LAMBDA(
+                       if(it.team == this.team)
+                               ++pcount;
+               ));
+               if (sdelay_small_count == 0)
+                       sdelay_small_count = 1;
+               if (sdelay_large_count == 0)
+                       sdelay_large_count = 1;
+       }
+       else
+       {
+               FOREACH_CLIENT(IS_PLAYER(it) && it != this, LAMBDA(
+                       ++pcount;
+               ));
+               if (sdelay_small_count == 0)
+               {
+                       if (g_cts)
+                       {
+                               // Players play independently. No point in requiring enemies.
+                               sdelay_small_count = 1;
+                       }
+                       else
+                       {
+                               // Players play AGAINST each other. Enemies required.
+                               sdelay_small_count = 2;
+                       }
+               }
+               if (sdelay_large_count == 0)
+               {
+                       if (g_cts)
+                       {
+                               // Players play independently. No point in requiring enemies.
+                               sdelay_large_count = 1;
+                       }
+                       else
+                       {
+                               // Players play AGAINST each other. Enemies required.
+                               sdelay_large_count = 2;
+                       }
+               }
+       }
+
+       float sdelay;
+
+       if (pcount <= sdelay_small_count)
+               sdelay = sdelay_small;
+       else if (pcount >= sdelay_large_count)
+               sdelay = sdelay_large;
+       else  // NOTE: this case implies sdelay_large_count > sdelay_small_count.
+               sdelay = sdelay_small + (sdelay_large - sdelay_small) * (pcount - sdelay_small_count) / (sdelay_large_count - sdelay_small_count);
+
+       if(waves)
+               this.respawn_time = ceil((time + sdelay) / waves) * waves;
+       else
+               this.respawn_time = time + sdelay;
+
+       if(sdelay < sdelay_max)
+               this.respawn_time_max = time + sdelay_max;
+       else
+               this.respawn_time_max = this.respawn_time;
+
+       if((sdelay + waves >= 5.0) && (this.respawn_time - time > 1.75))
+               this.respawn_countdown = 10; // first number to count down from is 10
+       else
+               this.respawn_countdown = -1; // do not count down
+
+       if(autocvar_g_forced_respawn)
+               this.respawn_flags = this.respawn_flags | RESPAWN_FORCE;
+}
+
+void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{
+       float take, save, dh, da;
+       vector v;
+       float valid_damage_for_weaponstats;
+       float excess;
+
+       dh = max(this.health, 0);
+       da = max(this.armorvalue, 0);
+
+       if(!DEATH_ISSPECIAL(deathtype))
+       {
+               damage *= sqrt(bound(1.0, this.cvar_cl_handicap, 100.0));
+               if(this != attacker)
+                       damage /= sqrt(bound(1.0, attacker.cvar_cl_handicap, 100.0));
+       }
+
+       if(DEATH_ISWEAPON(deathtype, WEP_TUBA))
+       {
+               // tuba causes blood to come out of the ears
+               vector ear1, ear2;
+               vector d;
+               float f;
+               ear1 = this.origin;
+               ear1_z += 0.125 * this.view_ofs.z + 0.875 * this.maxs.z; // 7/8
+               ear2 = ear1;
+               makevectors(this.angles);
+               ear1 += v_right * -10;
+               ear2 += v_right * +10;
+               d = inflictor.origin - this.origin;
+               if (d)
+                       f = (d * v_right) / vlen(d); // this is cos of angle of d and v_right!
+               else
+                       f = 0;  // Assum ecenter.
+               force = v_right * vlen(force);
+               Violence_GibSplash_At(ear1, force * -1, 2, bound(0, damage, 25) / 2 * (0.5 - 0.5 * f), this, attacker);
+               Violence_GibSplash_At(ear2, force,      2, bound(0, damage, 25) / 2 * (0.5 + 0.5 * f), this, attacker);
+               if(f > 0)
+               {
+                       hitloc = ear1;
+                       force = force * -1;
+               }
+               else
+               {
+                       hitloc = ear2;
+                       // force is already good
+               }
+       }
+       else
+               Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, this, attacker);
+
+
+       v = healtharmor_applydamage(this.armorvalue, autocvar_g_balance_armor_blockpercent, deathtype, damage);
+       take = v.x;
+       save = v.y;
+
+       if(attacker == this)
+       {
+               // don't reset pushltime for this damage as it may be an attempt to
+               // escape a lava pit or similar
+               //this.pushltime = 0;
+               this.istypefrag = 0;
+       }
+       else if(IS_PLAYER(attacker))
+       {
+               this.pusher = attacker;
+               this.pushltime = time + autocvar_g_maxpushtime;
+               this.istypefrag = PHYS_INPUT_BUTTON_CHAT(this);
+       }
+       else if(time < this.pushltime)
+       {
+               attacker = this.pusher;
+               this.pushltime = max(this.pushltime, time + 0.6);
+       }
+       else
+       {
+               this.pushltime = 0;
+               this.istypefrag = 0;
+       }
+
+       if (time < this.spawnshieldtime && autocvar_g_spawnshield_blockdamage < 1)
+       {
+               vector v = healtharmor_applydamage(this.armorvalue, max(0, autocvar_g_spawnshield_blockdamage), deathtype, damage);
+               take = v.x;
+               save = v.y;
+       }
+
+       MUTATOR_CALLHOOK(PlayerDamage_SplitHealthArmor, inflictor, attacker, this, force, take, save, deathtype, damage);
+       take = bound(0, M_ARGV(4, float), this.health);
+       save = bound(0, M_ARGV(5, float), this.armorvalue);
+       excess = max(0, damage - take - save);
+
+       if(sound_allowed(MSG_BROADCAST, attacker))
+       {
+               if (save > 10)
+                       sound (this, CH_SHOTS, SND_ARMORIMPACT, VOL_BASE, ATTEN_NORM);
+               else if (take > 30)
+                       sound (this, CH_SHOTS, SND_BODYIMPACT2, VOL_BASE, ATTEN_NORM);
+               else if (take > 10)
+                       sound (this, CH_SHOTS, SND_BODYIMPACT1, VOL_BASE, ATTEN_NORM); // FIXME possibly remove them?
+       }
+
+       if (take > 50)
+               Violence_GibSplash_At(hitloc, force * -0.1, 3, 1, this, attacker);
+       if (take > 100)
+               Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, this, attacker);
+
+       if (time >= this.spawnshieldtime || autocvar_g_spawnshield_blockdamage < 1)
+       {
+               if (!(this.flags & FL_GODMODE))
+               {
+                       this.armorvalue = this.armorvalue - save;
+                       this.health = this.health - take;
+                       // pause regeneration for 5 seconds
+                       if(take)
+                               this.pauseregen_finished = max(this.pauseregen_finished, time + autocvar_g_balance_pause_health_regen);
+
+                       if (time > this.pain_finished)          //Don't switch pain sequences like crazy
+                       {
+                               this.pain_finished = time + 0.5;        //Supajoe
+
+                               if(autocvar_sv_gentle < 1) {
+                                       if(this.classname != "body") // pain anim is BORKED on our ZYMs, FIXME remove this once we have good models
+                                       {
+                                               if (!this.animstate_override)
+                                               {
+                                                       if (random() > 0.5)
+                                                               animdecide_setaction(this, ANIMACTION_PAIN1, true);
+                                                       else
+                                                               animdecide_setaction(this, ANIMACTION_PAIN2, true);
+                                               }
+                                       }
+
+                                       if(sound_allowed(MSG_BROADCAST, attacker))
+                                       if((this.health < 2 * WEP_CVAR_PRI(blaster, damage) * autocvar_g_balance_selfdamagepercent + 1) || !(DEATH_WEAPONOF(deathtype).spawnflags & WEP_FLAG_CANCLIMB) || attacker != this) // WEAPONTODO: create separate limit for pain notification with laser
+                                       if(this.health > 1)
+                                       // exclude pain sounds for laserjumps as long as you aren't REALLY low on health and would die of the next two
+                                       {
+                                               if(deathtype == DEATH_FALL.m_id)
+                                                       PlayerSound(this, playersound_fall, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
+                                               else if(this.health > 75)
+                                                       PlayerSound(this, playersound_pain100, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
+                                               else if(this.health > 50)
+                                                       PlayerSound(this, playersound_pain75, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
+                                               else if(this.health > 25)
+                                                       PlayerSound(this, playersound_pain50, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
+                                               else
+                                                       PlayerSound(this, playersound_pain25, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
+                                       }
+                               }
+                       }
+
+                       // throw off bot aim temporarily
+                       float shake;
+                       if(IS_BOT_CLIENT(this) && this.health >= 1)
+                       {
+                               shake = damage * 5 / (bound(0,skill,100) + 1);
+                               this.v_angle_x = this.v_angle.x + (random() * 2 - 1) * shake;
+                               this.v_angle_y = this.v_angle.y + (random() * 2 - 1) * shake;
+                               this.v_angle_x = bound(-90, this.v_angle.x, 90);
+                       }
+               }
+               else
+                       this.max_armorvalue += (save + take);
+       }
+       this.dmg_save = this.dmg_save + save;//max(save - 10, 0);
+       this.dmg_take = this.dmg_take + take;//max(take - 10, 0);
+       this.dmg_inflictor = inflictor;
+
+       if (this != attacker) {
+               float realdmg = damage - excess;
+               if (IS_PLAYER(attacker)) {
+                       PlayerScore_Add(attacker, SP_DMG, realdmg);
+               }
+               if (IS_PLAYER(this)) {
+                       PlayerScore_Add(this, SP_DMGTAKEN, realdmg);
+               }
+       }
+
+       bool abot = (IS_BOT_CLIENT(attacker));
+       bool vbot = (IS_BOT_CLIENT(this));
+
+       valid_damage_for_weaponstats = 0;
+       Weapon awep = WEP_Null;
+
+       if(vbot || IS_REAL_CLIENT(this))
+       if(abot || IS_REAL_CLIENT(attacker))
+       if(attacker && this != attacker)
+       if(DIFF_TEAM(this, attacker))
+       {
+               if(DEATH_ISSPECIAL(deathtype))
+                       awep = PS(attacker).m_weapon;
+               else
+                       awep = DEATH_WEAPONOF(deathtype);
+               valid_damage_for_weaponstats = 1;
+       }
+
+       dh = dh - max(this.health, 0);
+       da = da - max(this.armorvalue, 0);
+       if(valid_damage_for_weaponstats)
+       {
+               WeaponStats_LogDamage(awep.m_id, abot, PS(this).m_weapon.m_id, vbot, dh + da);
+       }
+       if (dh + da)
+       {
+               MUTATOR_CALLHOOK(PlayerDamaged, attacker, this, dh, da, hitloc, deathtype);
+       }
+
+       if (this.health < 1)
+       {
+               float defer_ClientKill_Now_TeamChange;
+               defer_ClientKill_Now_TeamChange = false;
+
+               if(this.alivetime)
+               {
+                       PS_GR_P_ADDVAL(this, PLAYERSTATS_ALIVETIME, time - this.alivetime);
+                       this.alivetime = 0;
+               }
+
+               if(valid_damage_for_weaponstats)
+                       WeaponStats_LogKill(awep.m_id, abot, PS(this).m_weapon.m_id, vbot);
+
+               if(autocvar_sv_gentle < 1)
+               if(sound_allowed(MSG_BROADCAST, attacker))
+               {
+                       if(deathtype == DEATH_DROWN.m_id)
+                               PlayerSound(this, playersound_drown, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
+                       else
+                               PlayerSound(this, playersound_death, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
+               }
+
+               // get rid of kill indicator
+               if(this.killindicator)
+               {
+                       delete(this.killindicator);
+                       this.killindicator = NULL;
+                       if(this.killindicator_teamchange)
+                               defer_ClientKill_Now_TeamChange = true;
+
+                       if(this.classname == "body")
+                       if(deathtype == DEATH_KILL.m_id)
+                       {
+                               // for the lemmings fans, a small harmless explosion
+                               Send_Effect(EFFECT_ROCKET_EXPLODE, this.origin, '0 0 0', 1);
+                       }
+               }
+
+               // print an obituary message
+               if(this.classname != "body")
+                       Obituary (attacker, inflictor, this, deathtype);
+
+        // increment frag counter for used weapon type
+        Weapon w = DEATH_WEAPONOF(deathtype);
+        if(w != WEP_Null)
+       if(accuracy_isgooddamage(attacker, this))
+        attacker.accuracy.(accuracy_frags[w.m_id-1]) += 1;
+
+               MUTATOR_CALLHOOK(PlayerDies, inflictor, attacker, this, deathtype, damage);
+               excess = M_ARGV(4, float);
+
+               Weapon wep = PS(this).m_weapon;
+               /*for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+               {
+                       .entity weaponentity = weaponentities[slot];
+                       wep.wr_playerdeath(wep, this, weaponentity);
+               }*/
+               .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+               wep.wr_playerdeath(wep, this, weaponentity);
+
+               RemoveGrapplingHook(this);
+
+               Portal_ClearAllLater(this);
+
+               this.fixangle = true;
+
+               if(defer_ClientKill_Now_TeamChange)
+                       ClientKill_Now_TeamChange(this); // can turn player into spectator
+
+               // player could have been miraculously resuscitated ;)
+               // e.g. players in freezetag get frozen, they don't really die
+               if(this.health >= 1 || !(IS_PLAYER(this) || this.classname == "body"))
+                       return;
+
+               // when we get here, player actually dies
+
+               Unfreeze(this); // remove any icy remains
+               this.health = 0; // Unfreeze resets health, so we need to set it back
+
+               // clear waypoints
+               WaypointSprite_PlayerDead(this);
+               // throw a weapon
+               SpawnThrownWeapon(this, this.origin + (this.mins + this.maxs) * 0.5, PS(this).m_switchweapon.m_id);
+
+               // become fully visible
+               this.alpha = default_player_alpha;
+               // make the corpse upright (not tilted)
+               this.angles_x = 0;
+               this.angles_z = 0;
+               // don't spin
+               this.avelocity = '0 0 0';
+               // view from the floor
+               this.view_ofs = '0 0 -8';
+               // toss the corpse
+               set_movetype(this, MOVETYPE_TOSS);
+               // shootable corpse
+               this.solid = SOLID_CORPSE;
+               this.ballistics_density = autocvar_g_ballistics_density_corpse;
+               // don't stick to the floor
+               UNSET_ONGROUND(this);
+               // dying animation
+               this.deadflag = DEAD_DYING;
+
+               // when to allow respawn
+               calculate_player_respawn_time(this);
+
+               this.death_time = time;
+               if (random() < 0.5)
+                       animdecide_setstate(this, this.anim_state | ANIMSTATE_DEAD1, true);
+               else
+                       animdecide_setstate(this, this.anim_state | ANIMSTATE_DEAD2, true);
+               if (this.maxs.z > 5)
+               {
+                       this.maxs_z = 5;
+                       setsize(this, this.mins, this.maxs);
+               }
+               // set damage function to corpse damage
+               this.event_damage = PlayerCorpseDamage;
+               // call the corpse damage function just in case it wants to gib
+               this.event_damage(this, inflictor, attacker, excess, deathtype, hitloc, force);
+
+               // set up to fade out later
+               SUB_SetFade (this, time + 6 + random (), 1);
+               // reset body think wrapper broken by SUB_SetFade
+               if(this.classname == "body" && getthink(this) != CopyBody_Think) {
+                       this.CopyBody_think = getthink(this);
+                       this.CopyBody_nextthink = this.nextthink;
+                       setthink(this, CopyBody_Think);
+                       this.nextthink = time;
+               }
+
+               if(autocvar_sv_gentle > 0 || autocvar_ekg || this.classname == "body") {
+                       // remove corpse
+                       // clones don't run any animation code any more, so we must gib them when they die :(
+                       PlayerCorpseDamage(this, inflictor, attacker, autocvar_sv_gibhealth+1.0, deathtype, hitloc, force);
+               }
+
+               // reset fields the weapons may use just in case
+               FOREACH(Weapons, it != WEP_Null, LAMBDA(
+                       it.wr_resetplayer(it, this);
+                       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+                       {
+                               ATTACK_FINISHED_FOR(this, it.m_id, slot) = 0;
+                       }
+               ));
+       }
+}
+
+void MoveToTeam(entity client, int team_colour, int type)
+{
+       int lockteams_backup = lockteams;  // backup any team lock
+       lockteams = 0;  // disable locked teams
+       TeamchangeFrags(client);  // move the players frags
+       SetPlayerColors(client, team_colour - 1);  // set the players colour
+       Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE.m_id, client.origin, '0 0 0');  // kill the player
+       lockteams = lockteams_backup;  // restore the team lock
+       LogTeamchange(client.playerid, client.team, type);
+}
+
+/** print(), but only print if the server is not local */
+void dedicated_print(string input)
+{
+       if (server_is_dedicated) print(input);
+}
+
+/**
+ * message "": do not say, just test flood control
+ * return value:
+ *   1 = accept
+ *   0 = reject
+ *  -1 = fake accept
+ */
+int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodcontrol)
+{
+       if (!teamsay && !privatesay) if (substring(msgin, 0, 1) == " ")
+        msgin = substring(msgin, 1, -1); // work around DP say bug (say_team does not have this!)
+
+       msgin = formatmessage(source, msgin);
+
+    string colorstr;
+       if (!IS_PLAYER(source))
+               colorstr = "^0"; // black for spectators
+       else if(teamplay)
+               colorstr = Team_ColorCode(source.team);
+       else
+       {
+               colorstr = "";
+               teamsay = false;
+       }
+
+       if(intermission_running)
+               teamsay = false;
+
+    if (!source) {
+               colorstr = "";
+               teamsay = false;
+    }
+
+       if(msgin != "")
+               msgin = trigger_magicear_processmessage_forallears(source, teamsay, privatesay, msgin);
+
+       /*
+        * using bprint solves this... me stupid
+       // how can we prevent the message from appearing in a listen server?
+       // for now, just give "say" back and only handle say_team
+       if(!teamsay)
+       {
+               clientcommand(source, strcat("say ", msgin));
+               return;
+       }
+       */
+
+    string namestr = "";
+    if (source)
+        namestr = autocvar_g_chat_teamcolors ? playername(source) : source.netname;
+
+    string colorprefix = (strdecolorize(namestr) == namestr) ? "^3" : "^7";
+
+    string msgstr, cmsgstr;
+    string privatemsgprefix = string_null;
+    int privatemsgprefixlen = 0;
+       if (msgin == "") {
+        msgstr = cmsgstr = "";
+       } else {
+               if(privatesay)
+               {
+                       msgstr = strcat("\{1}\{13}* ", colorprefix, namestr, "^3 tells you: ^7");
+                       privatemsgprefixlen = strlen(msgstr);
+                       msgstr = strcat(msgstr, msgin);
+                       cmsgstr = strcat(colorstr, colorprefix, namestr, "^3 tells you:\n^7", msgin);
+                       if(autocvar_g_chat_teamcolors)
+                               privatemsgprefix = strcat("\{1}\{13}* ^3You tell ", playername(privatesay), ": ^7");
+                       else
+                               privatemsgprefix = strcat("\{1}\{13}* ^3You tell ", privatesay.netname, ": ^7");
+               }
+               else if(teamsay)
+               {
+                       if(strstrofs(msgin, "/me", 0) >= 0)
+                       {
+                               //msgin = strreplace("/me", "", msgin);
+                               //msgin = substring(msgin, 3, strlen(msgin));
+                               msgin = strreplace("/me", strcat(colorstr, "(", colorprefix, namestr, colorstr, ")^7"), msgin);
+                               msgstr = strcat("\{1}\{13}^4* ", "^7", msgin);
+                       }
+                       else
+                               msgstr = strcat("\{1}\{13}", colorstr, "(", colorprefix, namestr, colorstr, ") ^7", msgin);
+                       cmsgstr = strcat(colorstr, "(", colorprefix, namestr, colorstr, ")\n^7", msgin);
+               }
+               else
+               {
+                       if(strstrofs(msgin, "/me", 0) >= 0)
+                       {
+                               //msgin = strreplace("/me", "", msgin);
+                               //msgin = substring(msgin, 3, strlen(msgin));
+                               msgin = strreplace("/me", strcat(colorprefix, namestr), msgin);
+                               msgstr = strcat("\{1}^4* ", "^7", msgin);
+                       }
+                       else {
+                msgstr = "\{1}";
+                msgstr = strcat(msgstr, (namestr != "") ? strcat(colorprefix, namestr, "^7: ") : "^7");
+                msgstr = strcat(msgstr, msgin);
+            }
+                       cmsgstr = "";
+               }
+               msgstr = strcat(strreplace("\n", " ", msgstr), "\n"); // newlines only are good for centerprint
+       }
+
+       string fullmsgstr = msgstr;
+       string fullcmsgstr = cmsgstr;
+
+       // FLOOD CONTROL
+       int flood = 0;
+       var .float flood_field = floodcontrol_chat;
+       if(floodcontrol)
+       {
+               float flood_spl;
+               float flood_burst;
+               float flood_lmax;
+               float lines;
+               if(privatesay)
+               {
+                       flood_spl = autocvar_g_chat_flood_spl_tell;
+                       flood_burst = autocvar_g_chat_flood_burst_tell;
+                       flood_lmax = autocvar_g_chat_flood_lmax_tell;
+                       flood_field = floodcontrol_chattell;
+               }
+               else if(teamsay)
+               {
+                       flood_spl = autocvar_g_chat_flood_spl_team;
+                       flood_burst = autocvar_g_chat_flood_burst_team;
+                       flood_lmax = autocvar_g_chat_flood_lmax_team;
+                       flood_field = floodcontrol_chatteam;
+               }
+               else
+               {
+                       flood_spl = autocvar_g_chat_flood_spl;
+                       flood_burst = autocvar_g_chat_flood_burst;
+                       flood_lmax = autocvar_g_chat_flood_lmax;
+                       flood_field = floodcontrol_chat;
+               }
+               flood_burst = max(0, flood_burst - 1);
+               // to match explanation in default.cfg, a value of 3 must allow three-line bursts and not four!
+
+               // do flood control for the default line size
+               if(msgstr != "")
+               {
+                       getWrappedLine_remaining = msgstr;
+                       msgstr = "";
+                       lines = 0;
+                       while(getWrappedLine_remaining && (!flood_lmax || lines <= flood_lmax))
+                       {
+                               msgstr = strcat(msgstr, " ", getWrappedLineLen(82.4289758859709, strlennocol)); // perl averagewidth.pl < gfx/vera-sans.width
+                               ++lines;
+                       }
+                       msgstr = substring(msgstr, 1, strlen(msgstr) - 1);
+
+                       if(getWrappedLine_remaining != "")
+                       {
+                               msgstr = strcat(msgstr, "\n");
+                               flood = 2;
+                       }
+
+                       if (time >= source.(flood_field))
+                       {
+                               source.(flood_field) = max(time - flood_burst * flood_spl, source.(flood_field)) + lines * flood_spl;
+                       }
+                       else
+                       {
+                               flood = 1;
+                               msgstr = fullmsgstr;
+                       }
+               }
+               else
+               {
+                       if (time >= source.(flood_field))
+                               source.(flood_field) = max(time - flood_burst * flood_spl, source.(flood_field)) + flood_spl;
+                       else
+                               flood = 1;
+               }
+
+               if (timeout_status == TIMEOUT_ACTIVE) // when game is paused, no flood protection
+                       source.(flood_field) = flood = 0;
+       }
+
+    string sourcemsgstr, sourcecmsgstr;
+       if(flood == 2) // cannot happen for empty msgstr
+       {
+               if(autocvar_g_chat_flood_notify_flooder)
+               {
+                       sourcemsgstr = strcat(msgstr, "\n^3FLOOD CONTROL: ^7message too long, trimmed\n");
+                       sourcecmsgstr = "";
+               }
+               else
+               {
+                       sourcemsgstr = fullmsgstr;
+                       sourcecmsgstr = fullcmsgstr;
+               }
+               cmsgstr = "";
+       }
+       else
+       {
+               sourcemsgstr = msgstr;
+               sourcecmsgstr = cmsgstr;
+       }
+
+       if (!privatesay && source && !IS_PLAYER(source))
+       {
+               if (!intermission_running)
+                       if(teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !(warmup_stage || gameover)))
+                               teamsay = -1; // spectators
+       }
+
+       if(flood)
+               LOG_INFO("NOTE: ", playername(source), "^7 is flooding.\n");
+
+       // build sourcemsgstr by cutting off a prefix and replacing it by the other one
+       if(privatesay)
+               sourcemsgstr = strcat(privatemsgprefix, substring(sourcemsgstr, privatemsgprefixlen, -1));
+
+    int ret;
+       if(source.muted)
+       {
+               // always fake the message
+               ret = -1;
+       }
+       else if(flood == 1)
+       {
+               if (autocvar_g_chat_flood_notify_flooder)
+               {
+                       sprint(source, strcat("^3FLOOD CONTROL: ^7wait ^1", ftos(source.(flood_field) - time), "^3 seconds\n"));
+                       ret = 0;
+               }
+               else
+                       ret = -1;
+       }
+       else
+       {
+               ret = 1;
+       }
+
+       if(sourcemsgstr != "" && ret != 0)
+       {
+               if(ret < 0) // faked message, because the player is muted
+               {
+                       sprint(source, sourcemsgstr);
+                       if(sourcecmsgstr != "" && !privatesay)
+                               centerprint(source, sourcecmsgstr);
+               }
+               else if(privatesay) // private message, between 2 people only
+               {
+                       sprint(source, sourcemsgstr);
+                       sprint(privatesay, msgstr);
+                       if (!autocvar_g_chat_tellprivacy) { dedicated_print(msgstr); } // send to server console too if "tellprivacy" is disabled
+                       if(cmsgstr != "")
+                               centerprint(privatesay, cmsgstr);
+               }
+               else if ( teamsay && source.active_minigame )
+               {
+                       sprint(source, sourcemsgstr);
+                       dedicated_print(msgstr); // send to server console too
+                       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && it.active_minigame == source.active_minigame, sprint(it, msgstr));
+               }
+               else if(teamsay > 0) // team message, only sent to team mates
+               {
+                       sprint(source, sourcemsgstr);
+                       dedicated_print(msgstr); // send to server console too
+                       if(sourcecmsgstr != "")
+                               centerprint(source, sourcecmsgstr);
+                       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source && it.team == source.team, {
+                               sprint(it, msgstr);
+                               if(cmsgstr != "")
+                                       centerprint(it, cmsgstr);
+                       });
+               }
+               else if(teamsay < 0) // spectator message, only sent to spectators
+               {
+                       sprint(source, sourcemsgstr);
+                       dedicated_print(msgstr); // send to server console too
+                       FOREACH_CLIENT(!IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source, sprint(it, msgstr));
+               }
+               else
+               {
+            if (source) {
+                sprint(source, sourcemsgstr);
+                dedicated_print(msgstr); // send to server console too
+                MX_Say(strcat(playername(source), "^7: ", msgin));
+            }
+            FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source, sprint(it, msgstr));
+        }
+       }
+
+       return ret;
+}
diff --git a/qcsrc/server/player.qh b/qcsrc/server/player.qh
new file mode 100644 (file)
index 0000000..3e2b860
--- /dev/null
@@ -0,0 +1,41 @@
+#pragma once
+
+.entity pusher;
+.float pushltime;
+.float istypefrag;
+
+.float CopyBody_nextthink;
+.void(entity this) CopyBody_think;
+void CopyBody_Think(entity this);
+void CopyBody(entity this, float keepvelocity);
+
+void dedicated_print(string input);
+
+void player_setupanimsformodel(entity this);
+
+void player_anim(entity this);
+
+void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
+
+// g_<gametype>_str:
+// If 0, default is used.
+// If <0, 0 is used.
+// Otherwise, g_str (default value) is used.
+// For consistency, negative values there are mapped to zero too.
+#define GAMETYPE_DEFAULTED_SETTING(str) \
+       ((gametype_setting_tmp = cvar(strcat("g_", GetGametype(), "_" #str))), \
+       (gametype_setting_tmp < 0) ? 0 \
+       : (gametype_setting_tmp == 0 || autocvar_g_respawn_delay_forced) ? max(0, autocvar_g_##str) \
+       : gametype_setting_tmp)
+
+void calculate_player_respawn_time(entity this);
+
+void ClientKill_Now_TeamChange(entity this);
+
+void MoveToTeam(entity client, float team_colour, float type);
+
+void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
+
+/** to be used by `prvm_edictset server playernumber muted 1` */
+.float muted;
+int Say(entity source, float teamsay, entity privatesay, string msgin, float floodcontrol);
index 8a40b111840a34ebf2198ba53787d00fc59a8d2a..12083e423cb573b940c3c82c9453450447f6c096 100644 (file)
@@ -1,14 +1,14 @@
 #include "portals.qh"
 
 #include "g_hook.qh"
-#include "mutators/all.qh"
+#include "mutators/_mod.qh"
 #include "../common/constants.qh"
 #include "../common/deathtypes/all.qh"
 #include "../common/notifications/all.qh"
 #include "../common/triggers/teleporters.qh"
 #include "../common/triggers/subs.qh"
 #include "../common/util.qh"
-#include "../common/weapons/all.qh"
+#include <common/weapons/_all.qh>
 #include "../lib/csqcmodel/sv_model.qh"
 #include "../lib/warpzone/anglestransform.qh"
 #include "../lib/warpzone/util_server.qh"
index c49b604e69c0da8660bd9968a6c5680ce9cac6ab..1000a5105ba25da7332711ae91b3b6c3d0323f3e 100644 (file)
@@ -1,34 +1,11 @@
-#ifndef DEBUGPATHING
-       #define DEBUGPATHING 0
-#endif
-
 #include <lib/_all.inc>
 
 #if XONOTIC
-
-#include "_all.qh"
-
-#include "../server/_mod.inc"
-#include "bot/_mod.inc"
-#include "command/_mod.inc"
-#include "mutators/_mod.inc"
-#include "pathlib/_all.inc"
-#include "weapons/_mod.inc"
-
-#include <common/_all.inc>
-#include <common/effects/qc/all.qc>
-
-#include <lib/csqcmodel/sv_model.qc>
-
-#include <lib/warpzone/anglestransform.qc>
-#include <lib/warpzone/common.qc>
-#include <lib/warpzone/server.qc>
-#include <lib/warpzone/util_server.qc>
-
+#include <server/_all.inc>
 #endif
 
-#include <ecs/_lib.inc>
+#include <ecs/_mod.inc>
 
-#if BUILD_MOD
-#include "../../mod/server/progs.inc"
+#ifdef BUILD_MOD
+#include <mod/server/progs.inc>
 #endif
index b315d6cad4ac45b8513a842e8b8081a7a8dac81d..8fc38aa2c5e028ed1d44f8cd5f3b7128454ddda9 100644 (file)
@@ -1,6 +1,6 @@
 #include "race.qh"
 
-#include "cl_client.qh"
+#include "client.qh"
 #include "portals.qh"
 #include "scores.qh"
 #include "spawnpoints.qh"
@@ -832,15 +832,14 @@ void trigger_race_checkpoint_verify(entity this)
                                race_timed_checkpoint = 255;
                        }
                } else {
-                       for (entity cp = NULL; (cp = find(cp, classname, "trigger_race_checkpoint")); ) {
-                               if (cp.sprite) {
-                                       if (cp.race_checkpoint == 0) {
-                                               WaypointSprite_UpdateSprites(cp.sprite, WP_RaceStart, WP_Null, WP_Null);
-                    } else if (cp.race_checkpoint == race_timed_checkpoint) {
-                                               WaypointSprite_UpdateSprites(cp.sprite, WP_RaceFinish, WP_Null, WP_Null);
-                    }
+                       IL_EACH(g_racecheckpoints, it.sprite,
+                       {
+                               if (it.race_checkpoint == 0) {
+                                       WaypointSprite_UpdateSprites(it.sprite, WP_RaceStart, WP_Null, WP_Null);
+                } else if (it.race_checkpoint == race_timed_checkpoint) {
+                                       WaypointSprite_UpdateSprites(it.sprite, WP_RaceFinish, WP_Null, WP_Null);
                                }
-            }
+            });
                }
        }
 
@@ -946,6 +945,8 @@ spawnfunc(trigger_race_checkpoint)
        this.sprite.waypointsprite_visible_for_player = race_waypointsprite_visible_for_player;
        this.spawn_evalfunc = trigger_race_checkpoint_spawn_evalfunc;
 
+       IL_PUSH(g_racecheckpoints, this);
+
        InitializeEntity(this, trigger_race_checkpoint_verify, INITPRIO_FINDTARGET);
 }
 
@@ -1142,7 +1143,7 @@ float race_GetFractionalLapCount(entity e)
 
        vector o0, o1;
        float bestfraction, fraction;
-       entity lastcp, cp0, cp1;
+       entity lastcp;
        float nextcpindex, lastcpindex;
 
        nextcpindex = max(e.race_checkpoint, 0);
@@ -1153,26 +1154,26 @@ float race_GetFractionalLapCount(entity e)
                return l; // finish
 
        bestfraction = 1;
-       for(cp0 = NULL; (cp0 = find(cp0, classname, "trigger_race_checkpoint")); )
+       IL_EACH(g_racecheckpoints, true,
        {
-               if(cp0.race_checkpoint != lastcpindex)
+               if(it.race_checkpoint != lastcpindex)
                        continue;
                if(lastcp)
-                       if(cp0 != lastcp)
+                       if(it != lastcp)
                                continue;
-               o0 = (cp0.absmin + cp0.absmax) * 0.5;
-               for(cp1 = NULL; (cp1 = find(cp1, classname, "trigger_race_checkpoint")); )
+               o0 = (it.absmin + it.absmax) * 0.5;
+               IL_EACH(g_racecheckpoints, true,
                {
-                       if(cp1.race_checkpoint != nextcpindex)
+                       if(it.race_checkpoint != nextcpindex)
                                continue;
-                       o1 = (cp1.absmin + cp1.absmax) * 0.5;
+                       o1 = (it.absmin + it.absmax) * 0.5;
                        if(o0 == o1)
                                continue;
                        fraction = bound(0.0001, vlen(e.origin - o1) / vlen(o0 - o1), 1);
                        if(fraction < bestfraction)
                                bestfraction = fraction;
-               }
-       }
+               });
+       });
 
        // we are at CP "nextcpindex - bestfraction"
        // race_timed_checkpoint == 4: then nextcp==4 means 0.9999x, nextcp==0 means 0.0000x
index 6360b0ae5aba535b3727c36110ac5a85e099cce1..6419afb737690604dace62c681cabe9da377f4e7 100644 (file)
@@ -29,6 +29,9 @@ float race_completing;
 .float race_respawn_checkpoint;
 .entity race_respawn_spotref; // try THIS spawn in case you respawn
 
+IntrusiveList g_racecheckpoints;
+STATIC_INIT(g_racecheckpoints) { g_racecheckpoints = IL_NEW(); }
+
 // definitions for functions used outside race.qc
 float race_PreviousCheckpoint(float f);
 float race_NextCheckpoint(float f);
index e3d5fd9d72e5e0da5a904528c8ded99b87dd7a7e..94bea2b44a662428e8259e36a0b08941f18e91d3 100644 (file)
@@ -1,7 +1,7 @@
 #include "scores.qh"
 
 #include "command/common.qh"
-#include "mutators/all.qh"
+#include "mutators/_mod.qh"
 #include "../common/playerstats.qh"
 #include "../common/teams.qh"
 
index d3aceac50b2b28e8f2606d74ab4fe4713b12bba7..9c416472f40a207b0870c9bc5be4fc416502d48b 100644 (file)
@@ -1,6 +1,6 @@
 #include "scores_rules.qh"
 
-#include "cl_client.qh"
+#include "client.qh"
 #include "scores.qh"
 
 int ScoreRules_teams;
@@ -45,8 +45,8 @@ void ScoreRules_basics(int teams, float sprio, float stprio, float score_enabled
        if(score_enabled)
                ScoreInfo_SetLabel_PlayerScore(SP_SCORE,        "score",     sprio);
 
-       ScoreInfo_SetLabel_PlayerScore(SP_DMG, "damage", 0);
-       ScoreInfo_SetLabel_PlayerScore(SP_DMGTAKEN, "damagetaken", SFL_LOWER_IS_BETTER);
+       ScoreInfo_SetLabel_PlayerScore(SP_DMG, "dmg", 0);
+       ScoreInfo_SetLabel_PlayerScore(SP_DMGTAKEN, "dmgtaken", SFL_LOWER_IS_BETTER);
        ScoreInfo_SetLabel_PlayerScore(SP_ELO, "elo", 0);
 }
 void ScoreRules_basics_end()
index 958b0bd6e3a7c7ddf8ebefced698652592d80f19..59cc052af421942def992c27f5103fd3d08d00d8 100644 (file)
@@ -1,6 +1,6 @@
 #include "spawnpoints.qh"
 
-#include "mutators/all.qh"
+#include "mutators/_mod.qh"
 #include "g_world.qh"
 #include "race.qh"
 #include "../common/constants.qh"
@@ -166,6 +166,7 @@ spawnfunc(info_player_start)
 spawnfunc(info_player_deathmatch)
 {
        this.classname = "info_player_deathmatch";
+       IL_PUSH(g_spawnpoints, this);
        relocate_spawnpoint(this);
 }
 
@@ -333,7 +334,7 @@ entity SelectSpawnPoint(entity this, bool anypoint)
        float teamcheck;
        entity spot, firstspot;
 
-       spot = find (NULL, classname, "testplayerstart");
+       spot = find(NULL, classname, "testplayerstart");
        if (spot)
                return spot;
 
index c69230d88fce5f09b5d277f13ae72a15c8c451e8..1544fa384a5cbbf16eb4cebf3bf89be17faf1c1f 100644 (file)
@@ -7,10 +7,11 @@
 /**
     Uniform pull towards a point
 **/
-vector steerlib_pull(entity this, vector point)
+#define steerlib_pull(ent,point) normalize(point - (ent).origin)
+/*vector steerlib_pull(entity this, vector point)
 {
     return normalize(point - this.origin);
-}
+}*/
 
 /**
     Uniform push from a point
@@ -143,7 +144,7 @@ vector steerlib_wander(entity this, float range, float tresh, vector oldpoint)
     vector wander_point;
     wander_point = v_forward - oldpoint;
 
-    if (vlen(wander_point) > tresh)
+    if (vdist(wander_point, >, tresh))
         return oldpoint;
 
     range = bound(0,range,1);
index fa21610f042d29c794149cb2a28a0ec02a824569..4beb69f6328ba6c337d3b34e803104464e8a73d3 100644 (file)
@@ -4,4 +4,4 @@
 
 vector steerlib_arrive(entity this, vector point, float maximal_distance);
 vector steerlib_attract2(entity this, vector point, float min_influense, float max_distance, float max_influense);
-vector steerlib_pull(entity this, vector point);
+//vector steerlib_pull(entity this, vector point);
index 4a72bb1aee81d2444355b7d305d37ed83b32c13c..ea11ea36a613f25ffb8c3f9915c8fa3dbf9c58f0 100644 (file)
@@ -8,7 +8,7 @@
 
 #include "command/common.qh"
 
-#include "mutators/all.qh"
+#include "mutators/_mod.qh"
 #include "weapons/csqcprojectile.qh"
 
 #include "../common/constants.qh"
@@ -18,7 +18,7 @@
 #include "../common/util.qh"
 
 #include "../common/vehicles/all.qh"
-#include "../common/weapons/all.qh"
+#include <common/weapons/_all.qh>
 
 #include "../lib/csqcmodel/sv_model.qh"
 
@@ -159,8 +159,8 @@ void sys_phys_update(entity this, float dt);
 void StartFrame()
 {
     // TODO: if move is more than 50ms, split it into two moves (this matches QWSV behavior and the client prediction)
-    FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), sys_phys_update(it, frametime));
-    FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), PlayerPreThink(it));
+    IL_EACH(g_players, IS_FAKE_CLIENT(it), sys_phys_update(it, frametime));
+    IL_EACH(g_players, IS_FAKE_CLIENT(it), PlayerPreThink(it));
 
        execute_next_frame();
        if (autocvar_sv_autopause && !server_is_dedicated) Pause_TryPause(true);
@@ -191,7 +191,7 @@ void StartFrame()
        }
 #endif
 
-       FOREACH_ENTITY_FLOAT(csqcprojectile_clientanimate, true, CSQCProjectile_Check(it));
+       IL_EACH(g_projectiles, it.csqcprojectile_clientanimate, CSQCProjectile_Check(it));
 
        if (RedirectionThink()) return;
 
@@ -229,7 +229,7 @@ void StartFrame()
        MUTATOR_CALLHOOK(SV_StartFrame);
 
     FOREACH_CLIENT(true, GlobalStats_update(it));
-    FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), PlayerPostThink(it));
+    IL_EACH(g_players, IS_FAKE_CLIENT(it), PlayerPostThink(it));
 }
 
 .vector originjitter;
index 8589ecc7df3ce24aeab612d96f37ff0622d1c09b..dac8f193001de334cd0e19e2838176a86f26721c 100644 (file)
@@ -1,6 +1,6 @@
 #include "t_quake.qh"
 
-#include "../common/weapons/all.qh"
+#include <common/weapons/_all.qh>
 
 spawnfunc(weapon_electro);
 spawnfunc(weapon_hagar);
index 1bdb49765d76127e40bfd69b7b26c74713cd8a0c..254130f88c443cd4105e65ed20210faa4bbbb849 100644 (file)
@@ -1,6 +1,6 @@
 #include "t_quake3.qh"
 
-#include "../common/weapons/all.qh"
+#include <common/weapons/_all.qh>
 
 spawnfunc(weapon_crylink);
 spawnfunc(weapon_electro);
@@ -97,41 +97,41 @@ spawnfunc(target_init)
 // weapon give ent from defrag
 void target_give_init(entity this)
 {
-       entity targ;
-       for (targ = NULL; (targ = find(targ, targetname, this.target)); ) {
-               if (targ.classname == "weapon_rocketlauncher" || targ.classname == "weapon_devastator") {
-                       this.ammo_rockets += targ.count * WEP_CVAR(devastator, ammo);
+       IL_EACH(g_items, it.targetname == this.target,
+       {
+               if (it.classname == "weapon_rocketlauncher" || it.classname == "weapon_devastator") {
+                       this.ammo_rockets += it.count * WEP_CVAR(devastator, ammo);
                        this.netname = "devastator";
                }
-               else if (targ.classname == "weapon_plasmagun") {
-                       this.ammo_rockets += targ.count * WEP_CVAR_PRI(hagar, ammo); // WEAPONTODO
+               else if (it.classname == "weapon_plasmagun") {
+                       this.ammo_rockets += it.count * WEP_CVAR_PRI(hagar, ammo); // WEAPONTODO
                        if(this.netname == "")
                                this.netname = "hagar";
                        else
                                this.netname = strcat(this.netname, " hagar");
                }
-               else if (targ.classname == "weapon_bfg") {
-                       this.ammo_cells += targ.count * WEP_CVAR_PRI(crylink, ammo);
+               else if (it.classname == "weapon_bfg") {
+                       this.ammo_cells += it.count * WEP_CVAR_PRI(crylink, ammo);
                        if(this.netname == "")
                                this.netname = "crylink";
                        else
                                this.netname = strcat(this.netname, " crylink");
                }
-               else if (targ.classname == "weapon_grenadelauncher" || targ.classname == "weapon_mortar") {
-                       this.ammo_rockets += targ.count * WEP_CVAR_PRI(mortar, ammo); // WEAPONTODO
+               else if (it.classname == "weapon_grenadelauncher" || it.classname == "weapon_mortar") {
+                       this.ammo_rockets += it.count * WEP_CVAR_PRI(mortar, ammo); // WEAPONTODO
                        if(this.netname == "")
                                this.netname = "mortar";
                        else
                                this.netname = strcat(this.netname, " mortar");
                }
-               else if (targ.classname == "item_armor_body")
+               else if (it.classname == "item_armor_body")
                        this.armorvalue = 100;
-               else if (targ.classname == "item_health_mega")
+               else if (it.classname == "item_health_mega")
                        this.health = 200;
-               //remove(targ); // removing ents in init functions causes havoc, workaround:
-        setthink(targ, SUB_Remove);
-        targ.nextthink = time;
-       }
+               //remove(it); // removing ents in init functions causes havoc, workaround:
+        setthink(it, SUB_Remove);
+        it.nextthink = time;
+       });
        this.spawnflags = 2;
        spawnfunc_target_items(this);
        InitializeEntity(this, target_init_verify, INITPRIO_FINDTARGET);
index 61a9d2fadd52f4292bff1cf0719378939f726b39..de7f2f992617320717d079bd86ea8c8c68f91ed6 100644 (file)
@@ -1,6 +1,6 @@
 #include "teamplay.qh"
 
-#include "cl_client.qh"
+#include "client.qh"
 #include "race.qh"
 #include "scores.qh"
 #include "scores_rules.qh"
@@ -9,10 +9,10 @@
 
 #include "command/vote.qh"
 
-#include "mutators/all.qh"
+#include "mutators/_mod.qh"
 
 #include "../common/deathtypes/all.qh"
-#include "../common/gamemodes/all.qh"
+#include "../common/gamemodes/_mod.qh"
 #include "../common/teams.qh"
 
 void TeamchangeFrags(entity e)
@@ -158,6 +158,16 @@ string getwelcomemessage(entity this)
        return s;
 }
 
+void setcolor(entity this, int clr)
+{
+#if 0
+       this.clientcolors = clr;
+       this.team = (clr & 15) + 1;
+#else
+       builtin_setcolor(this, clr);
+#endif
+}
+
 void SetPlayerColors(entity pl, float _color)
 {
        /*string s;
@@ -542,7 +552,7 @@ int JoinBestTeam(entity this, bool only_return_best, bool forcebestteam)
                                SetPlayerColors(this, selectedteam - 1);
 
                                // when JoinBestTeam is called by client.qc/ClientKill_Now_TeamChange the players team is -1 and thus skipped
-                               // when JoinBestTeam is called by cl_client.qc/ClientConnect the player_id is 0 the log attempt is rejected
+                               // when JoinBestTeam is called by client.qc/ClientConnect the player_id is 0 the log attempt is rejected
                                LogTeamchange(this.playerid, this.team, 99);
                        }
                        return selectedteam;
index f34c6d59df438b491090956b2e7782153f3f7da3..127ac7a6d30caffc887e9571c40104148813eadb 100644 (file)
@@ -50,3 +50,5 @@ int JoinBestTeam(entity this, bool only_return_best, bool forcebestteam);
 //void() ctf_playerchanged;
 
 void ShufflePlayerOutOfTeam (float source_team);
+
+void setcolor(entity this, int clr);
index be6445b48e4c696ca82ffef01dd7207807229754..e6d6f66a0d0442ef426980cf355006af81698fd6 100644 (file)
@@ -1,11 +1,11 @@
 #pragma once
 
 #include "autocvars.qh"
-#include "cl_client.qh"
-#include "command/all.qh"
+#include "client.qh"
+#include "command/_mod.qh"
 #include "weapons/common.qh"
 #include "weapons/selection.qh"
 #include <common/items/item.qh>
 #include <common/physics/player.qh>
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 #include <common/vehicles/all.qh>
index 9efc4ce6a0700f31511eb9dfb2c9a5ae56e92cb9..ed9006bb25eb493e2af8b5bfdb2dde217c5d0e70 100644 (file)
@@ -1,10 +1,10 @@
 #include "accuracy.qh"
 
-#include "../mutators/all.qh"
+#include "../mutators/_mod.qh"
 #include <common/constants.qh>
 #include <common/teams.qh>
 #include <common/util.qh>
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 
 int accuracy_byte(float n, float d)
 {
index 954f82564fb9a5e17a8ee49924987c3c45e22a00..03031c1580ac20a1ea3765190e4a58feda89c88a 100644 (file)
@@ -5,8 +5,8 @@
 #include <common/deathtypes/all.qh>
 #include <common/notifications/all.qh>
 #include <common/util.qh>
-#include <common/weapons/all.qh>
-#include <common/items/all.qc>
+#include <common/weapons/_all.qh>
+#include <common/items/_mod.qh>
 
 void W_GiveWeapon(entity e, int wep)
 {
index caa367e5d708ac96ef0f047a7fb3f1fdeac299c0..a8a893e217700750b4364106ba7fd6065ac3ae8f 100644 (file)
@@ -5,7 +5,7 @@
 #include "../command/common.qh"
 
 #include <common/constants.qh>
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 
 .float csqcprojectile_type;
 
index ec1fd089b1abd6cfeaf7fae56bf9d7546e975b0e..372f7357b4057a95d63cba482b826d87b23a441d 100644 (file)
@@ -2,7 +2,7 @@
 
 #include "../antilag.qh"
 #include "../g_subs.qh"
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 #include <common/state.qh>
 
 vector W_HitPlotUnnormalizedUntransform(vector screenforward, vector screenright, vector screenup, vector v)
index ff5eaa59a41e187b7a29f4f6939a4f042b7d8806..56df6c3a2c47e615562c1bd190eba45241536c3f 100644 (file)
@@ -5,7 +5,7 @@
 #include <common/constants.qh>
 #include <common/util.qh>
 #include <common/items/item.qh>
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 #include <common/state.qh>
 #include <common/mutators/mutator/waypoints/waypointsprites.qh>
 
@@ -21,12 +21,10 @@ void Send_WeaponComplain(entity e, float wpn, float type)
 void Weapon_whereis(Weapon this, entity cl)
 {
        if (!autocvar_g_showweaponspawns) return;
-       FOREACH_ENTITY_FLOAT(weapon, this.m_id,
+       IL_EACH(g_items, it.weapon == this.m_id,
        {
                if (it.classname == "droppedweapon" && autocvar_g_showweaponspawns < 2)
                        continue;
-               if (!(it.flags & FL_ITEM))
-                       continue;
                entity wp = WaypointSprite_Spawn(
                        WP_Weapon,
                        -2, 0,
index faec22f307315b37f06b47b40d72d0e64cb272e5..00bc0e5d12397c2e608cae53f245a1593d2d3e3c 100644 (file)
@@ -1,9 +1,9 @@
 #include "spawning.qh"
 
 #include "weaponsystem.qh"
-#include "../mutators/all.qh"
+#include "../mutators/_mod.qh"
 #include <common/t_items.qh>
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 
 string W_Apply_Weaponreplace(string in)
 {
@@ -29,7 +29,7 @@ void weapon_defaultspawnfunc(entity this, Weapon e)
        {
                if (e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
                {
-                       LOG_MAPWARNF("Attempted to spawn a mutator-blocked weapon rejected: prvm_edict server %i", this);
+                       LOG_WARNF("Attempted to spawn a mutator-blocked weapon rejected: prvm_edict server %i", this);
                        startitem_failed = true;
                        return;
                }
index 7cc7580c17dd8922b894cc141e47fd63de9d70a0..c06b90ec2d98434d3940cb075b235baffb7451a2 100644 (file)
@@ -1,7 +1,7 @@
 #include "throwing.qh"
 
 #include "weaponsystem.qh"
-#include "../mutators/all.qh"
+#include "../mutators/_mod.qh"
 #include <common/t_items.qh>
 #include "../g_damage.qh"
 #include <common/items/item.qh>
@@ -9,7 +9,7 @@
 #include <common/notifications/all.qh>
 #include <common/triggers/subs.qh>
 #include <common/util.qh>
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 #include <common/state.qh>
 
 void thrown_wep_think(entity this)
index f773180fea091f1621a03b1886aba93a3ed9ee69..176b69e6b6c9e5f720f2dfc09fb9af13367c1ff8 100644 (file)
@@ -12,7 +12,7 @@
 #include <common/constants.qh>
 #include <common/util.qh>
 
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 #include <common/state.qh>
 
 #include <lib/warpzone/common.qh>
index 2b4be7e917f32fb71bd0b9f1a375399af03344c2..2ffb1c1ec8dfa60403d672d524f5239af73da64f 100644 (file)
@@ -2,7 +2,7 @@
 
 #include "../g_world.qh"
 
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 
 void WeaponStats_Init()
 {
index 2efea3ff5ee3da4c36bde9914ebe0b98615304e6..2a6cd03a4daec752658f6f92d6107b4ea3bdd3ab 100644 (file)
@@ -3,15 +3,15 @@
 #include "selection.qh"
 
 #include "../command/common.qh"
-#include "../mutators/all.qh"
+#include "../mutators/_mod.qh"
 #include "../round_handler.qh"
 #include <common/t_items.qh>
 #include <common/animdecide.qh>
 #include <common/constants.qh>
-#include <common/monsters/all.qh>
+#include <common/monsters/_mod.qh>
 #include <common/notifications/all.qh>
 #include <common/util.qh>
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 #include <common/state.qh>
 #include <lib/csqcmodel/sv_model.qh>
 
diff --git a/qcsrc/tools/auto-super.pl b/qcsrc/tools/auto-super.pl
new file mode 100644 (file)
index 0000000..00926d0
--- /dev/null
@@ -0,0 +1,101 @@
+my %classoffile = ();
+my %classes = ();
+my %baseclass = ();
+my %methods = ();
+my %attrs = ();
+my %methodnames = ();
+my %old2new = ();
+
+print STDERR "Scanning...\n";
+for my $f(@ARGV)
+{
+       open my $fh, '<', $f;
+       while(<$fh>)
+       {
+               if(/^CLASS\(([^)]*)\)(?:\s*EXTENDS\(([^)]*)\))?/)
+               {
+                       $classes{$1} = defined($2) ? $2 : "Object";
+                       $classoffile{$f} = $1;
+               }
+               if(/^\s*METHOD\(([^),]*),\s*([^),]*)/)
+               {
+                       $methods{$1}{$2} = $1;
+                       $methodnames{"$1"."_"."$2"} = $f;
+                       $old2new{"$2$1"} = "$1"."_"."$2";
+               }
+               if(/^\s*ATTRIB(?:ARRAY)?\(([^),]*),\s*([^),]*)/)
+               {
+                       $attrs{$1}{$2} = $1;
+               }
+       }
+       close $fh;
+}
+
+# propagate down methods etc.
+print STDERR "Propagating...\n";
+for my $class(keys %classes)
+{
+       print STDERR "$class";
+       my $base = $class;
+       for(;;)
+       {
+               $base = $classes{$base};
+               last if not defined $base;
+               print STDERR " -> $base";
+               while(my ($method, $definingclass) = each %{$methods{$base}})
+               {
+                       $methods{$class}{$method} = $definingclass
+                               if not defined $methods{$class}{$method};
+               }
+               while(my ($attr, $definingclass) = each %{$attrs{$base}})
+               {
+                       $attrs{$class}{$attr} = $definingclass
+                               if not defined $attrs{$class}{$attr};
+               }
+       }
+       print STDERR "\n";
+}
+
+# change all calls to base method to super, complain about skipping
+print STDERR "Fixing...\n";
+for my $f(@ARGV)
+{
+       open my $fh, '<', $f;
+       my $s = do { undef local $/; <$fh>; };
+       my $s0 = $s;
+       close $fh;
+
+       my $class = $classoffile{$f};
+       my $base = $classes{$class};
+       next if not defined $base;
+
+       for(keys %old2new)
+       {
+               $s =~ s/\b$_\b/$old2new{$_}/g;
+       }
+
+       my @methods_super = map { [ $methods{$base}{$_} . "_" . $_, "SUPER($class).$_" ]; } keys %{$methods{$base}};
+       for(@methods_super)
+       {
+               my ($search, $replace) = @$_;
+               my $n = ($s =~ s/\b$search\b/$replace/g);
+               print STDERR "[$f] $search -> $replace... $n replacements\n"
+                       if $n;
+       }
+
+       for(grep { $methodnames{$_} ne $f } keys %methodnames)
+       {
+               if($s =~ /\b$_\b/)
+               {
+                       print STDERR "[$f] calls non-super external method directly: $_\n";
+               }
+       }
+
+       if($s ne $s0)
+       {
+               print STDERR "Rewriting $f...\n";
+               open my $fh, '>', $f;
+               print $fh $s;
+               close $fh;
+       }
+}
index 2fa17825ec1394d8b5efddc7db85513a7c00ca8c..ebb232105f51a66d03770486c0afe3950c44f7fb 100755 (executable)
@@ -11,7 +11,6 @@ declare -a QCCDEFS=(
     -DNDEBUG=1
     -DXONOTIC=1
     -DWATERMARK="\"$(git describe --tags --dirty='~')\""
-    -DDEBUGPATHING=0
 )
 QCCDEFS="${QCCDEFS[@]}"
 
@@ -35,23 +34,22 @@ QCCFLAGS="${QCCFLAGS[@]} ${NOWARN[@]}"
 cd ..
 
 function check1() {
-    declare -l base="${1}"
-    MODE=${2}
-    declare -l file="${3}"
+    declare -l prog="${1}"
+    declare -l file="${2}"
+    MODE=${prog}
     qpp ${file} test.dat \
-            -include lib/_all.inc -include ${base}/_all.qh \
-            -I. ${QCCIDENT} ${QCCDEFS} -D${MODE} > ${WORKDIR}/${MODE}.qc
-    qcc ${QCCFLAGS} -o ../${WORKDIR}/test.dat ../${WORKDIR}/${MODE}.qc >/dev/null
+            -include lib/_all.inc -include ${prog}/_all.qh \
+            -I. ${QCCIDENT} ${QCCDEFS} > ${WORKDIR}/${prog}.qc
+    qcc ${QCCFLAGS} -o ../${WORKDIR}/test.dat ../${WORKDIR}/${prog}.qc >/dev/null
 }
 
 function check() {
-    declare -l base="${1}"
-    MODE=${2}
-    find ${base} -type f -name '*.qc' -print0 | sort -z | while read -r -d '' file; do
-        check1 ${base} ${MODE} ${file}
+    declare -l prog="${1}"
+    find ${prog} -type f -name '*.qc' -print0 | sort -z | while read -r -d '' file; do
+        check1 ${prog} ${file}
     done
 }
 
-check client CSQC
-check server SVQC
-check menu MENUQC
+check client
+check server
+check menu
index 2c34e671344a11b8caf392715f92f0d29c8b3580..9a3ba10987b05622ad8873ee16783475a9f09b98 100755 (executable)
@@ -12,21 +12,36 @@ function genmod() {
     echo '// generated file; do not modify' > ${MOD}.inc
     echo '// generated file; do not modify' > ${MOD}.qh
     for f in $(ls | sort -k 1,1 -t .); do
-        if [[ "$f" == cl_* ]]; then if [[ -f "${f#cl_}" ]]; then continue; fi; fi
-        if [[ "$f" == sv_* ]]; then if [[ -f "${f#sv_}" ]]; then continue; fi; fi
-        if [[ "$f" == ui_* ]]; then if [[ -f "${f#ui_}" ]]; then continue; fi; fi
+          if [[ "$f" == cl_* ]]; then f="${f#cl_}"; if [[ -f "$f" ]]; then continue; fi
+        elif [[ "$f" == sv_* ]]; then f="${f#sv_}"; if [[ -f "$f" ]]; then continue; fi
+        elif [[ "$f" == ui_* ]]; then f="${f#ui_}"; if [[ -f "$f" ]]; then continue; fi
+        fi
         if [[ "$f" == *.qc ]]; then
-            echo "#include <${CTX}$f>" >> ${MOD}.inc
-            echo "#include <${CTX}${f%.qc}.qh>" >> ${MOD}.qh
+            if [[ -f "$f" ]]; then echo -e "#include <${CTX}$f>" >> ${MOD}.inc; fi
+            if [[ -f "${f%.qc}.qh" ]]; then echo -e "#include <${CTX}${f%.qc}.qh>" >> ${MOD}.qh; fi
             if [[ -f "cl_$f" ]]; then echo -e "#ifdef CSQC\n    #include <${CTX}cl_$f>\n#endif" >> ${MOD}.inc; fi
+            if [[ -f "cl_${f%.qc}.qh" ]]; then echo -e "#ifdef CSQC\n    #include <${CTX}cl_${f%.qc}.qh>\n#endif" >> ${MOD}.qh; fi
             if [[ -f "sv_$f" ]]; then echo -e "#ifdef SVQC\n    #include <${CTX}sv_$f>\n#endif" >> ${MOD}.inc; fi
+            if [[ -f "sv_${f%.qc}.qh" ]]; then echo -e "#ifdef SVQC\n    #include <${CTX}sv_${f%.qc}.qh>\n#endif" >> ${MOD}.qh; fi
             if [[ -f "ui_$f" ]]; then echo -e "#ifdef MENUQC\n    #include <${CTX}ui_$f>\n#endif" >> ${MOD}.inc; fi
+            if [[ -f "ui_${f%.qc}.qh" ]]; then echo -e "#ifdef MENUQC\n    #include <${CTX}ui_${f%.qc}.qh>\n#endif" >> ${MOD}.qh; fi
         fi
     done
-    # echo >> ${MOD}
+    declare -l rec=1
+    if [[ -f "_all.inc" ]]; then rec=0; fi
     for f in *; do if [ -d "$f" ]; then
         (cd -- "$f" && genmod)
-        # echo "#include \"$f/MOD\"" >> ${MOD}
+        if [[ $rec == 1 ]]; then
+            rec=2
+            echo >> ${MOD}.inc
+            echo >> ${MOD}.qh
+        fi
+        if [[ $rec != 0 ]]; then
+            declare -l mod=_mod
+            if [[ -f "$f/_all.inc" ]]; then mod=_all; fi
+            echo "#include <${CTX}$f/${mod}.inc>" >> ${MOD}.inc
+            echo "#include <${CTX}$f/${mod}.qh>" >> ${MOD}.qh
+        fi
     fi; done
 }
 
index daf20ebf3ba748a68be9a1712be73c532f605fa9..924083166f08e0650e4c08f624eded6b6835822c 100755 (executable)
@@ -17,7 +17,7 @@ function check() {
     find "$base" -type f -name '*.qc' -print0 | sort -z | while read -r -d '' file; do
         echo "$file"
         declare -l file_h="${file%.qc}.qh"
-        if [ ! -f "$file_h" ]; then echo "#pragma once" > "$file_h"; fi
+        if [[ ! -f "$file_h" ]]; then echo "#pragma once" > "$file_h"; fi
 
         include=$(basename "$file")
         include="${include%.qc}.qh"
@@ -33,3 +33,4 @@ function check() {
 check client
 check server
 check menu
+check common
index b115c196ecc75f4bb1ea0bcef52c15f962b9169c..9951ec2fd7837645d812c9bc56e449dde0a05cdb 100755 (executable)
@@ -12,15 +12,23 @@ QCCFLAGS=${QCCFLAGS}
 function qpp() {
     IN=$1
     OUT=$2
-    >&2 echo + ${CPP} ${@:3} ${IN}
+    case ${MODE} in
+        client) DEFS="-DGAMEQC -DCSQC"
+        ;;
+        menu) DEFS="-DMENUQC"
+        ;;
+        server) DEFS="-DGAMEQC -DSVQC"
+        ;;
+    esac
+    >&2 echo + ${CPP} ${@:3} ${DEFS} ${IN}
     set +e
     # additional information
-    ${CPP} ${@:3} \
+    ${CPP} ${@:3} ${DEFS} \
         -dM 1>${WORKDIR}/${MODE}_macros.txt \
         -H 2>${WORKDIR}/${MODE}_includes.txt \
         ${IN}
     # main step
-    ${CPP} ${@:3} -MMD -MP -MT ${OUT} -Wall -Wundef -Werror ${IN} -o ${WORKDIR}/${MODE}.txt
+    ${CPP} ${@:3} ${DEFS} -MMD -MP -MT ${OUT} -Wall -Wundef -Werror ${IN} -o ${WORKDIR}/${MODE}.txt
     err=$?
     set -e
     if [ ${err} -ne 0 ]; then return ${err}; fi
@@ -37,16 +45,6 @@ $(return >/dev/null 2>&1) || {
     MODE=$1
     OUT=$2
     IN=$3
-
-    case ${MODE} in
-        client) PROG=CSQC
-        ;;
-        menu) PROG=MENUQC
-        ;;
-        server) PROG=SVQC
-        ;;
-    esac
-
-    qpp ${IN} ${OUT} -I. ${QCCIDENT} ${QCCDEFS} -D${PROG} > ${WORKDIR}/${MODE}.qc
+    qpp ${IN} ${OUT} -I. ${QCCIDENT} ${QCCDEFS} > ${WORKDIR}/${MODE}.qc
     qcc ${QCCFLAGS} -o ${OUT} ../${WORKDIR}/${MODE}.qc
 }